1 /* $OpenBSD: clnt_tcp.c,v 1.36 2022/07/15 17:33:28 deraadt 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 const 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 int ct_connected; /* pre-connected */ 84 struct timeval ct_wait; 85 bool_t ct_waitset; /* wait set by clnt_control? */ 86 struct sockaddr_in ct_addr; 87 struct rpc_err ct_error; 88 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 89 u_int ct_mpos; /* pos after marshal */ 90 XDR ct_xdrs; 91 }; 92 93 static int readtcp(struct ct_data *, caddr_t, int); 94 static int writetcp(struct ct_data *, caddr_t, int); 95 96 /* 97 * Create a client handle for a tcp/ip connection. 98 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 99 * connected to raddr. If *sockp non-negative then 100 * raddr is ignored. The rpc/tcp package does buffering 101 * similar to stdio, so the client must pick send and receive buffer sizes,]; 102 * 0 => use the default. 103 * If raddr->sin_port is 0, then a binder on the remote machine is 104 * consulted for the right port number. 105 * NB: *sockp is copied into a private area. 106 * NB: It is the client's responsibility to close *sockp, unless 107 * clnttcp_create() was called with *sockp = -1 (so it created 108 * the socket), and CLNT_DESTROY() is used. 109 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 110 * something more useful. 111 */ 112 CLIENT * 113 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 114 u_int sendsz, u_int recvsz) 115 { 116 CLIENT *h; 117 struct ct_data *ct = NULL; 118 struct rpc_msg call_msg; 119 120 h = (CLIENT *)mem_alloc(sizeof(*h)); 121 if (h == NULL) { 122 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 123 rpc_createerr.cf_error.re_errno = errno; 124 goto fooy; 125 } 126 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 127 if (ct == NULL) { 128 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 129 rpc_createerr.cf_error.re_errno = errno; 130 goto fooy; 131 } 132 133 /* 134 * If no port number given ask the pmap for one 135 */ 136 if (raddr->sin_port == 0) { 137 u_short port; 138 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 139 mem_free((caddr_t)ct, sizeof(struct ct_data)); 140 mem_free((caddr_t)h, sizeof(CLIENT)); 141 return (NULL); 142 } 143 raddr->sin_port = htons(port); 144 } 145 146 /* 147 * If no socket given, open one 148 */ 149 if (*sockp < 0) { 150 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 151 (void)bindresvport(*sockp, NULL); 152 if ((*sockp == -1) 153 || (connect(*sockp, (struct sockaddr *)raddr, 154 sizeof(*raddr)) == -1)) { 155 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 156 rpc_createerr.cf_error.re_errno = errno; 157 if (*sockp != -1) 158 (void)close(*sockp); 159 goto fooy; 160 } 161 ct->ct_closeit = TRUE; 162 } else { 163 ct->ct_closeit = FALSE; 164 } 165 166 /* 167 * Set up private data struct 168 */ 169 ct->ct_sock = *sockp; 170 ct->ct_wait.tv_usec = 0; 171 ct->ct_waitset = FALSE; 172 ct->ct_addr = *raddr; 173 174 /* 175 * Initialize call message 176 */ 177 call_msg.rm_xid = arc4random(); 178 call_msg.rm_direction = CALL; 179 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 180 call_msg.rm_call.cb_prog = prog; 181 call_msg.rm_call.cb_vers = vers; 182 183 /* 184 * pre-serialize the static part of the call msg and stash it away 185 */ 186 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 187 XDR_ENCODE); 188 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 189 if (ct->ct_closeit) { 190 (void)close(*sockp); 191 } 192 goto fooy; 193 } 194 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 195 XDR_DESTROY(&(ct->ct_xdrs)); 196 197 /* 198 * Create a client handle which uses xdrrec for serialization 199 * and authnone for authentication. 200 */ 201 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 202 (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, 203 (int(*)(caddr_t, caddr_t, int))writetcp); 204 h->cl_ops = &tcp_ops; 205 h->cl_private = (caddr_t) ct; 206 h->cl_auth = authnone_create(); 207 if (h->cl_auth == NULL) { 208 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 209 rpc_createerr.cf_error.re_errno = errno; 210 goto fooy; 211 } 212 return (h); 213 214 fooy: 215 /* 216 * Something goofed, free stuff and barf 217 */ 218 if (ct) 219 mem_free((caddr_t)ct, sizeof(struct ct_data)); 220 if (h) 221 mem_free((caddr_t)h, sizeof(CLIENT)); 222 return (NULL); 223 } 224 DEF_WEAK(clnttcp_create); 225 226 static enum clnt_stat 227 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 228 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 229 { 230 struct ct_data *ct = (struct ct_data *) h->cl_private; 231 XDR *xdrs = &(ct->ct_xdrs); 232 struct rpc_msg reply_msg; 233 u_long x_id; 234 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 235 bool_t shipnow; 236 int refreshes = 2; 237 238 if (!ct->ct_waitset) { 239 ct->ct_wait = timeout; 240 } 241 242 shipnow = 243 (xdr_results == NULL && timeout.tv_sec == 0 244 && timeout.tv_usec == 0) ? FALSE : TRUE; 245 246 call_again: 247 xdrs->x_op = XDR_ENCODE; 248 ct->ct_error.re_status = RPC_SUCCESS; 249 x_id = ntohl(--(*msg_x_id)); 250 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 251 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 252 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 253 (! (*xdr_args)(xdrs, args_ptr))) { 254 if (ct->ct_error.re_status == RPC_SUCCESS) 255 ct->ct_error.re_status = RPC_CANTENCODEARGS; 256 (void)xdrrec_endofrecord(xdrs, TRUE); 257 return (ct->ct_error.re_status); 258 } 259 if (! xdrrec_endofrecord(xdrs, shipnow)) 260 return (ct->ct_error.re_status = RPC_CANTSEND); 261 if (! shipnow) 262 return (RPC_SUCCESS); 263 /* 264 * Hack to provide rpc-based message passing 265 */ 266 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 267 return(ct->ct_error.re_status = RPC_TIMEDOUT); 268 } 269 270 271 /* 272 * Keep receiving until we get a valid transaction id 273 */ 274 xdrs->x_op = XDR_DECODE; 275 while (TRUE) { 276 reply_msg.acpted_rply.ar_verf = _null_auth; 277 reply_msg.acpted_rply.ar_results.where = NULL; 278 reply_msg.acpted_rply.ar_results.proc = xdr_void; 279 if (! xdrrec_skiprecord(xdrs)) 280 return (ct->ct_error.re_status); 281 /* now decode and validate the response header */ 282 if (! xdr_replymsg(xdrs, &reply_msg)) { 283 if (ct->ct_error.re_status == RPC_SUCCESS) 284 continue; 285 return (ct->ct_error.re_status); 286 } 287 if (reply_msg.rm_xid == x_id) 288 break; 289 } 290 291 /* 292 * process header 293 */ 294 _seterr_reply(&reply_msg, &(ct->ct_error)); 295 if (ct->ct_error.re_status == RPC_SUCCESS) { 296 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 297 ct->ct_error.re_status = RPC_AUTHERROR; 298 ct->ct_error.re_why = AUTH_INVALIDRESP; 299 } else if (! (*xdr_results)(xdrs, results_ptr)) { 300 if (ct->ct_error.re_status == RPC_SUCCESS) 301 ct->ct_error.re_status = RPC_CANTDECODERES; 302 } 303 /* free verifier ... */ 304 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 305 xdrs->x_op = XDR_FREE; 306 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 307 } 308 } /* end successful completion */ 309 else { 310 /* maybe our credentials need to be refreshed ... */ 311 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 312 goto call_again; 313 } /* end of unsuccessful completion */ 314 return (ct->ct_error.re_status); 315 } 316 317 static void 318 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 319 { 320 struct ct_data *ct = 321 (struct ct_data *) h->cl_private; 322 323 *errp = ct->ct_error; 324 } 325 326 static bool_t 327 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 328 { 329 struct ct_data *ct = (struct ct_data *)cl->cl_private; 330 XDR *xdrs = &(ct->ct_xdrs); 331 332 xdrs->x_op = XDR_FREE; 333 return ((*xdr_res)(xdrs, res_ptr)); 334 } 335 336 static void 337 clnttcp_abort(CLIENT *clnt) 338 { 339 } 340 341 static bool_t 342 clnttcp_control(CLIENT *cl, u_int request, void *info) 343 { 344 struct ct_data *ct = (struct ct_data *)cl->cl_private; 345 346 switch (request) { 347 case CLSET_TIMEOUT: 348 ct->ct_wait = *(struct timeval *)info; 349 ct->ct_waitset = TRUE; 350 break; 351 case CLGET_TIMEOUT: 352 *(struct timeval *)info = ct->ct_wait; 353 break; 354 case CLGET_SERVER_ADDR: 355 *(struct sockaddr_in *)info = ct->ct_addr; 356 break; 357 case CLSET_CONNECTED: 358 ct->ct_connected = *(int *)info; 359 break; 360 default: 361 return (FALSE); 362 } 363 return (TRUE); 364 } 365 366 367 static void 368 clnttcp_destroy(CLIENT *h) 369 { 370 struct ct_data *ct = 371 (struct ct_data *) h->cl_private; 372 373 if (ct->ct_closeit && ct->ct_sock != -1) { 374 (void)close(ct->ct_sock); 375 } 376 XDR_DESTROY(&(ct->ct_xdrs)); 377 mem_free((caddr_t)ct, sizeof(struct ct_data)); 378 mem_free((caddr_t)h, sizeof(CLIENT)); 379 } 380 381 /* 382 * Interface between xdr serializer and tcp connection. 383 * Behaves like the system calls, read & write, but keeps some error state 384 * around for the rpc level. 385 */ 386 static int 387 readtcp(struct ct_data *ct, caddr_t buf, int len) 388 { 389 struct pollfd pfd[1]; 390 struct timespec start, after, duration, delta, wait; 391 int r, save_errno; 392 393 if (len == 0) 394 return (0); 395 396 pfd[0].fd = ct->ct_sock; 397 pfd[0].events = POLLIN; 398 TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait); 399 delta = wait; 400 WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); 401 for (;;) { 402 r = ppoll(pfd, 1, &delta, NULL); 403 save_errno = errno; 404 405 WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); 406 timespecsub(&start, &after, &duration); 407 timespecsub(&wait, &duration, &delta); 408 if (delta.tv_sec < 0 || !timespecisset(&delta)) 409 r = 0; 410 411 switch (r) { 412 case 0: 413 ct->ct_error.re_status = RPC_TIMEDOUT; 414 return (-1); 415 case 1: 416 if (pfd[0].revents & POLLNVAL) 417 errno = EBADF; 418 else if (pfd[0].revents & POLLERR) 419 errno = EIO; 420 else 421 break; 422 /* FALLTHROUGH */ 423 case -1: 424 if (errno == EINTR) 425 continue; 426 ct->ct_error.re_status = RPC_CANTRECV; 427 ct->ct_error.re_errno = save_errno; 428 return (-1); 429 } 430 break; 431 } 432 433 switch (len = read(ct->ct_sock, buf, len)) { 434 case 0: 435 /* premature eof */ 436 ct->ct_error.re_errno = ECONNRESET; 437 ct->ct_error.re_status = RPC_CANTRECV; 438 len = -1; /* it's really an error */ 439 break; 440 case -1: 441 ct->ct_error.re_errno = errno; 442 ct->ct_error.re_status = RPC_CANTRECV; 443 break; 444 } 445 return (len); 446 } 447 448 static int 449 writetcp(struct ct_data *ct, caddr_t buf, int len) 450 { 451 int i, cnt; 452 453 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 454 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 455 ct->ct_error.re_errno = errno; 456 ct->ct_error.re_status = RPC_CANTSEND; 457 return (-1); 458 } 459 } 460 return (len); 461 } 462