1 /* $OpenBSD: clnt_tcp.c,v 1.34 2020/07/06 13:33:06 pirofti Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 36 * 37 * TCP based RPC supports 'batched calls'. 38 * A sequence of calls may be batched-up in a send buffer. The rpc call 39 * return immediately to the client even though the call was not necessarily 40 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 41 * the rpc timeout value is zero (see clnt.h, rpc). 42 * 43 * Clients should NOT casually batch calls that in fact return results; that is, 44 * the server side should be aware that a call is batched and not produce any 45 * return message. Batched calls that produce many result messages can 46 * deadlock (netlock) the client and the server.... 47 * 48 * Now go hang yourself. 49 */ 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <rpc/rpc.h> 56 #include <sys/socket.h> 57 #include <netdb.h> 58 #include <errno.h> 59 #include <rpc/pmap_clnt.h> 60 61 #define MCALL_MSG_SIZE 24 62 63 static enum clnt_stat clnttcp_call(CLIENT *, u_long, xdrproc_t, caddr_t, 64 xdrproc_t, caddr_t, struct timeval); 65 static void clnttcp_abort(CLIENT *); 66 static void clnttcp_geterr(CLIENT *, struct rpc_err *); 67 static bool_t clnttcp_freeres(CLIENT *, xdrproc_t, caddr_t); 68 static bool_t clnttcp_control(CLIENT *, u_int, void *); 69 static void clnttcp_destroy(CLIENT *); 70 71 static struct clnt_ops tcp_ops = { 72 clnttcp_call, 73 clnttcp_abort, 74 clnttcp_geterr, 75 clnttcp_freeres, 76 clnttcp_destroy, 77 clnttcp_control 78 }; 79 80 struct ct_data { 81 int ct_sock; 82 bool_t ct_closeit; 83 struct timeval ct_wait; 84 bool_t ct_waitset; /* wait set by clnt_control? */ 85 struct sockaddr_in ct_addr; 86 struct rpc_err ct_error; 87 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 88 u_int ct_mpos; /* pos after marshal */ 89 XDR ct_xdrs; 90 }; 91 92 static int readtcp(struct ct_data *, caddr_t, int); 93 static int writetcp(struct ct_data *, caddr_t, int); 94 95 /* 96 * Create a client handle for a tcp/ip connection. 97 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 98 * connected to raddr. If *sockp non-negative then 99 * raddr is ignored. The rpc/tcp package does buffering 100 * similar to stdio, so the client must pick send and receive buffer sizes,]; 101 * 0 => use the default. 102 * If raddr->sin_port is 0, then a binder on the remote machine is 103 * consulted for the right port number. 104 * NB: *sockp is copied into a private area. 105 * NB: It is the client's responsibility to close *sockp, unless 106 * clnttcp_create() was called with *sockp = -1 (so it created 107 * the socket), and CLNT_DESTROY() is used. 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(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 113 u_int sendsz, u_int recvsz) 114 { 115 CLIENT *h; 116 struct ct_data *ct = NULL; 117 struct rpc_msg call_msg; 118 119 h = (CLIENT *)mem_alloc(sizeof(*h)); 120 if (h == NULL) { 121 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 122 rpc_createerr.cf_error.re_errno = errno; 123 goto fooy; 124 } 125 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 126 if (ct == NULL) { 127 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 128 rpc_createerr.cf_error.re_errno = errno; 129 goto fooy; 130 } 131 132 /* 133 * If no port number given ask the pmap for one 134 */ 135 if (raddr->sin_port == 0) { 136 u_short port; 137 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 138 mem_free((caddr_t)ct, sizeof(struct ct_data)); 139 mem_free((caddr_t)h, sizeof(CLIENT)); 140 return (NULL); 141 } 142 raddr->sin_port = htons(port); 143 } 144 145 /* 146 * If no socket given, open one 147 */ 148 if (*sockp < 0) { 149 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 150 (void)bindresvport(*sockp, NULL); 151 if ((*sockp == -1) 152 || (connect(*sockp, (struct sockaddr *)raddr, 153 sizeof(*raddr)) == -1)) { 154 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 155 rpc_createerr.cf_error.re_errno = errno; 156 if (*sockp != -1) 157 (void)close(*sockp); 158 goto fooy; 159 } 160 ct->ct_closeit = TRUE; 161 } else { 162 ct->ct_closeit = FALSE; 163 } 164 165 /* 166 * Set up private data struct 167 */ 168 ct->ct_sock = *sockp; 169 ct->ct_wait.tv_usec = 0; 170 ct->ct_waitset = FALSE; 171 ct->ct_addr = *raddr; 172 173 /* 174 * Initialize call message 175 */ 176 call_msg.rm_xid = arc4random(); 177 call_msg.rm_direction = CALL; 178 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 179 call_msg.rm_call.cb_prog = prog; 180 call_msg.rm_call.cb_vers = vers; 181 182 /* 183 * pre-serialize the static part of the call msg and stash it away 184 */ 185 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 186 XDR_ENCODE); 187 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 188 if (ct->ct_closeit) { 189 (void)close(*sockp); 190 } 191 goto fooy; 192 } 193 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 194 XDR_DESTROY(&(ct->ct_xdrs)); 195 196 /* 197 * Create a client handle which uses xdrrec for serialization 198 * and authnone for authentication. 199 */ 200 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 201 (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, 202 (int(*)(caddr_t, caddr_t, int))writetcp); 203 h->cl_ops = &tcp_ops; 204 h->cl_private = (caddr_t) ct; 205 h->cl_auth = authnone_create(); 206 if (h->cl_auth == NULL) { 207 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 208 rpc_createerr.cf_error.re_errno = errno; 209 goto fooy; 210 } 211 return (h); 212 213 fooy: 214 /* 215 * Something goofed, free stuff and barf 216 */ 217 if (ct) 218 mem_free((caddr_t)ct, sizeof(struct ct_data)); 219 if (h) 220 mem_free((caddr_t)h, sizeof(CLIENT)); 221 return (NULL); 222 } 223 DEF_WEAK(clnttcp_create); 224 225 static enum clnt_stat 226 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 227 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 228 { 229 struct ct_data *ct = (struct ct_data *) h->cl_private; 230 XDR *xdrs = &(ct->ct_xdrs); 231 struct rpc_msg reply_msg; 232 u_long x_id; 233 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 234 bool_t shipnow; 235 int refreshes = 2; 236 237 if (!ct->ct_waitset) { 238 ct->ct_wait = timeout; 239 } 240 241 shipnow = 242 (xdr_results == NULL && timeout.tv_sec == 0 243 && timeout.tv_usec == 0) ? FALSE : TRUE; 244 245 call_again: 246 xdrs->x_op = XDR_ENCODE; 247 ct->ct_error.re_status = RPC_SUCCESS; 248 x_id = ntohl(--(*msg_x_id)); 249 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 250 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 251 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 252 (! (*xdr_args)(xdrs, args_ptr))) { 253 if (ct->ct_error.re_status == RPC_SUCCESS) 254 ct->ct_error.re_status = RPC_CANTENCODEARGS; 255 (void)xdrrec_endofrecord(xdrs, TRUE); 256 return (ct->ct_error.re_status); 257 } 258 if (! xdrrec_endofrecord(xdrs, shipnow)) 259 return (ct->ct_error.re_status = RPC_CANTSEND); 260 if (! shipnow) 261 return (RPC_SUCCESS); 262 /* 263 * Hack to provide rpc-based message passing 264 */ 265 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 266 return(ct->ct_error.re_status = RPC_TIMEDOUT); 267 } 268 269 270 /* 271 * Keep receiving until we get a valid transaction id 272 */ 273 xdrs->x_op = XDR_DECODE; 274 while (TRUE) { 275 reply_msg.acpted_rply.ar_verf = _null_auth; 276 reply_msg.acpted_rply.ar_results.where = NULL; 277 reply_msg.acpted_rply.ar_results.proc = xdr_void; 278 if (! xdrrec_skiprecord(xdrs)) 279 return (ct->ct_error.re_status); 280 /* now decode and validate the response header */ 281 if (! xdr_replymsg(xdrs, &reply_msg)) { 282 if (ct->ct_error.re_status == RPC_SUCCESS) 283 continue; 284 return (ct->ct_error.re_status); 285 } 286 if (reply_msg.rm_xid == x_id) 287 break; 288 } 289 290 /* 291 * process header 292 */ 293 _seterr_reply(&reply_msg, &(ct->ct_error)); 294 if (ct->ct_error.re_status == RPC_SUCCESS) { 295 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 296 ct->ct_error.re_status = RPC_AUTHERROR; 297 ct->ct_error.re_why = AUTH_INVALIDRESP; 298 } else if (! (*xdr_results)(xdrs, results_ptr)) { 299 if (ct->ct_error.re_status == RPC_SUCCESS) 300 ct->ct_error.re_status = RPC_CANTDECODERES; 301 } 302 /* free verifier ... */ 303 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 304 xdrs->x_op = XDR_FREE; 305 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 306 } 307 } /* end successful completion */ 308 else { 309 /* maybe our credentials need to be refreshed ... */ 310 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 311 goto call_again; 312 } /* end of unsuccessful completion */ 313 return (ct->ct_error.re_status); 314 } 315 316 static void 317 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 318 { 319 struct ct_data *ct = 320 (struct ct_data *) h->cl_private; 321 322 *errp = ct->ct_error; 323 } 324 325 static bool_t 326 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 327 { 328 struct ct_data *ct = (struct ct_data *)cl->cl_private; 329 XDR *xdrs = &(ct->ct_xdrs); 330 331 xdrs->x_op = XDR_FREE; 332 return ((*xdr_res)(xdrs, res_ptr)); 333 } 334 335 static void 336 clnttcp_abort(CLIENT *clnt) 337 { 338 } 339 340 static bool_t 341 clnttcp_control(CLIENT *cl, u_int request, void *info) 342 { 343 struct ct_data *ct = (struct ct_data *)cl->cl_private; 344 345 switch (request) { 346 case CLSET_TIMEOUT: 347 ct->ct_wait = *(struct timeval *)info; 348 ct->ct_waitset = TRUE; 349 break; 350 case CLGET_TIMEOUT: 351 *(struct timeval *)info = ct->ct_wait; 352 break; 353 case CLGET_SERVER_ADDR: 354 *(struct sockaddr_in *)info = ct->ct_addr; 355 break; 356 default: 357 return (FALSE); 358 } 359 return (TRUE); 360 } 361 362 363 static void 364 clnttcp_destroy(CLIENT *h) 365 { 366 struct ct_data *ct = 367 (struct ct_data *) h->cl_private; 368 369 if (ct->ct_closeit && ct->ct_sock != -1) { 370 (void)close(ct->ct_sock); 371 } 372 XDR_DESTROY(&(ct->ct_xdrs)); 373 mem_free((caddr_t)ct, sizeof(struct ct_data)); 374 mem_free((caddr_t)h, sizeof(CLIENT)); 375 } 376 377 /* 378 * Interface between xdr serializer and tcp connection. 379 * Behaves like the system calls, read & write, but keeps some error state 380 * around for the rpc level. 381 */ 382 static int 383 readtcp(struct ct_data *ct, caddr_t buf, int len) 384 { 385 struct pollfd pfd[1]; 386 struct timespec start, after, duration, delta, wait; 387 int r, save_errno; 388 389 if (len == 0) 390 return (0); 391 392 pfd[0].fd = ct->ct_sock; 393 pfd[0].events = POLLIN; 394 TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait); 395 delta = wait; 396 WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); 397 for (;;) { 398 r = ppoll(pfd, 1, &delta, NULL); 399 save_errno = errno; 400 401 WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); 402 timespecsub(&start, &after, &duration); 403 timespecsub(&wait, &duration, &delta); 404 if (delta.tv_sec < 0 || !timespecisset(&delta)) 405 r = 0; 406 407 switch (r) { 408 case 0: 409 ct->ct_error.re_status = RPC_TIMEDOUT; 410 return (-1); 411 case 1: 412 if (pfd[0].revents & POLLNVAL) 413 errno = EBADF; 414 else if (pfd[0].revents & POLLERR) 415 errno = EIO; 416 else 417 break; 418 /* FALLTHROUGH */ 419 case -1: 420 if (errno == EINTR) 421 continue; 422 ct->ct_error.re_status = RPC_CANTRECV; 423 ct->ct_error.re_errno = save_errno; 424 return (-1); 425 } 426 break; 427 } 428 429 switch (len = read(ct->ct_sock, buf, len)) { 430 case 0: 431 /* premature eof */ 432 ct->ct_error.re_errno = ECONNRESET; 433 ct->ct_error.re_status = RPC_CANTRECV; 434 len = -1; /* it's really an error */ 435 break; 436 case -1: 437 ct->ct_error.re_errno = errno; 438 ct->ct_error.re_status = RPC_CANTRECV; 439 break; 440 } 441 return (len); 442 } 443 444 static int 445 writetcp(struct ct_data *ct, caddr_t buf, int len) 446 { 447 int i, cnt; 448 449 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 450 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 451 ct->ct_error.re_errno = errno; 452 ct->ct_error.re_status = RPC_CANTSEND; 453 return (-1); 454 } 455 } 456 return (len); 457 } 458