1 /* $OpenBSD: svc_tcp.c,v 1.41 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 * svc_tcp.c, Server side for TCP/IP based RPC. 36 * 37 * Actually implements two flavors of transporter - 38 * a tcp rendezvouser (a listner and connection establisher) 39 * and a record/tcp stream. 40 */ 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <rpc/rpc.h> 47 #include <sys/socket.h> 48 #include <errno.h> 49 50 #include <netinet/in.h> 51 #include <netinet/ip.h> 52 #include <netinet/ip_var.h> 53 54 /* 55 * Ops vector for TCP/IP based rpc service handle 56 */ 57 static bool_t svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg); 58 static enum xprt_stat svctcp_stat(SVCXPRT *xprt); 59 static bool_t svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, 60 caddr_t args_ptr); 61 static bool_t svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg); 62 static bool_t svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, 63 caddr_t args_ptr); 64 static void svctcp_destroy(SVCXPRT *xprt); 65 66 static struct xp_ops svctcp_op = { 67 svctcp_recv, 68 svctcp_stat, 69 svctcp_getargs, 70 svctcp_reply, 71 svctcp_freeargs, 72 svctcp_destroy 73 }; 74 75 /* 76 * Ops vector for TCP/IP rendezvous handler 77 */ 78 static bool_t rendezvous_request(SVCXPRT *xprt, struct rpc_msg *); 79 static enum xprt_stat rendezvous_stat(SVCXPRT *xprt); 80 81 static struct xp_ops svctcp_rendezvous_op = { 82 rendezvous_request, 83 rendezvous_stat, 84 /* XXX abort illegal in library */ 85 (bool_t (*)(struct __rpc_svcxprt *, xdrproc_t, caddr_t))abort, 86 (bool_t (*)(struct __rpc_svcxprt *, struct rpc_msg *))abort, 87 (bool_t (*)(struct __rpc_svcxprt *, xdrproc_t, caddr_t))abort, 88 svctcp_destroy 89 }; 90 91 static int readtcp(SVCXPRT *xprt, caddr_t buf, int len), 92 writetcp(SVCXPRT *xprt, caddr_t buf, int len); 93 static SVCXPRT *makefd_xprt(int fd, u_int sendsize, u_int recvsize); 94 95 struct tcp_rendezvous { /* kept in xprt->xp_p1 */ 96 u_int sendsize; 97 u_int recvsize; 98 }; 99 100 struct tcp_conn { /* kept in xprt->xp_p1 */ 101 enum xprt_stat strm_stat; 102 u_long x_id; 103 XDR xdrs; 104 char verf_body[MAX_AUTH_BYTES]; 105 }; 106 107 /* 108 * Usage: 109 * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); 110 * 111 * Creates, registers, and returns a (rpc) tcp based transporter. 112 * Once *xprt is initialized, it is registered as a transporter 113 * see (svc.h, xprt_register). This routine returns 114 * a NULL if a problem occurred. 115 * 116 * If sock<0 then a socket is created, else sock is used. 117 * If the socket, sock is not bound to a port then svctcp_create 118 * binds it to an arbitrary port. The routine then starts a tcp 119 * listener on the socket's associated port. In any (successful) case, 120 * xprt->xp_sock is the registered socket number and xprt->xp_port is the 121 * associated port number. 122 * 123 * Since tcp streams do buffered io similar to stdio, the caller can specify 124 * how big the send and receive buffers are via the second and third parms; 125 * 0 => use the system default. 126 */ 127 SVCXPRT * 128 svctcp_create(int sock, u_int sendsize, u_int recvsize) 129 { 130 bool_t madesock = FALSE; 131 SVCXPRT *xprt; 132 struct tcp_rendezvous *r; 133 struct sockaddr_in addr; 134 socklen_t len = sizeof(struct sockaddr_in); 135 136 if (sock == RPC_ANYSOCK) { 137 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) 138 return (NULL); 139 madesock = TRUE; 140 } 141 memset(&addr, 0, sizeof (addr)); 142 addr.sin_len = sizeof(struct sockaddr_in); 143 addr.sin_family = AF_INET; 144 if (bindresvport(sock, &addr) == -1) { 145 addr.sin_port = 0; 146 (void)bind(sock, (struct sockaddr *)&addr, len); 147 } 148 if ((getsockname(sock, (struct sockaddr *)&addr, &len) == -1) || 149 (listen(sock, 2) != 0)) { 150 if (madesock) 151 (void)close(sock); 152 return (NULL); 153 } 154 r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); 155 if (r == NULL) { 156 if (madesock) 157 (void)close(sock); 158 return (NULL); 159 } 160 r->sendsize = sendsize; 161 r->recvsize = recvsize; 162 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 163 if (xprt == NULL) { 164 if (madesock) 165 (void)close(sock); 166 free(r); 167 return (NULL); 168 } 169 xprt->xp_p2 = NULL; 170 xprt->xp_p1 = (caddr_t)r; 171 xprt->xp_verf = _null_auth; 172 xprt->xp_ops = &svctcp_rendezvous_op; 173 xprt->xp_port = ntohs(addr.sin_port); 174 xprt->xp_sock = sock; 175 if (__xprt_register(xprt) == 0) { 176 if (madesock) 177 (void)close(sock); 178 free(r); 179 free(xprt); 180 return (NULL); 181 } 182 return (xprt); 183 } 184 DEF_WEAK(svctcp_create); 185 186 /* 187 * Like svtcp_create(), except the routine takes any *open* UNIX file 188 * descriptor as its first input. 189 */ 190 SVCXPRT * 191 svcfd_create(int fd, u_int sendsize, u_int recvsize) 192 { 193 194 return (makefd_xprt(fd, sendsize, recvsize)); 195 } 196 197 static SVCXPRT * 198 makefd_xprt(int fd, u_int sendsize, u_int recvsize) 199 { 200 SVCXPRT *xprt; 201 struct tcp_conn *cd; 202 203 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 204 if (xprt == NULL) 205 goto done; 206 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 207 if (cd == NULL) { 208 mem_free((char *) xprt, sizeof(SVCXPRT)); 209 xprt = NULL; 210 goto done; 211 } 212 cd->strm_stat = XPRT_IDLE; 213 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 214 (caddr_t)xprt, (int(*)(caddr_t, caddr_t, int))readtcp, 215 (int(*)(caddr_t, caddr_t, int))writetcp); 216 xprt->xp_p2 = NULL; 217 xprt->xp_p1 = (caddr_t)cd; 218 xprt->xp_verf.oa_base = cd->verf_body; 219 xprt->xp_addrlen = 0; 220 xprt->xp_ops = &svctcp_op; /* truely deals with calls */ 221 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 222 xprt->xp_sock = fd; 223 if (__xprt_register(xprt) == 0) { 224 free(xprt); 225 free(cd); 226 return (NULL); 227 } 228 done: 229 return (xprt); 230 } 231 232 static bool_t 233 rendezvous_request(SVCXPRT *xprt, struct rpc_msg *ignored) 234 { 235 int sock; 236 struct tcp_rendezvous *r; 237 struct sockaddr_in addr; 238 socklen_t len; 239 240 r = (struct tcp_rendezvous *)xprt->xp_p1; 241 again: 242 len = sizeof(struct sockaddr_in); 243 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, 244 &len)) == -1) { 245 if (errno == EINTR || errno == EWOULDBLOCK || 246 errno == ECONNABORTED) 247 goto again; 248 return (FALSE); 249 } 250 251 #ifdef IP_OPTIONS 252 { 253 struct ipoption opts; 254 socklen_t optsize = sizeof(opts); 255 int i; 256 257 if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, 258 (char *)&opts, &optsize) == 0 && 259 optsize != 0) { 260 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 261 optsize; ) { 262 u_char c = (u_char)opts.ipopt_list[i]; 263 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 264 close(sock); 265 return (FALSE); 266 } 267 if (c == IPOPT_EOL) 268 break; 269 i += (c == IPOPT_NOP) ? 1 : 270 (u_char)opts.ipopt_list[i+1]; 271 } 272 } 273 } 274 #endif 275 276 /* 277 * XXX careful for ftp bounce attacks. If discovered, close the 278 * socket and look for another connection. 279 */ 280 if (addr.sin_port == htons(20)) { 281 close(sock); 282 return (FALSE); 283 } 284 285 /* 286 * make a new transporter (re-uses xprt) 287 */ 288 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 289 xprt->xp_raddr = addr; 290 xprt->xp_addrlen = len; 291 return (FALSE); /* there is never an rpc msg to be processed */ 292 } 293 294 static enum xprt_stat 295 rendezvous_stat(SVCXPRT *xprt) 296 { 297 298 return (XPRT_IDLE); 299 } 300 301 static void 302 svctcp_destroy(SVCXPRT *xprt) 303 { 304 struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 305 306 xprt_unregister(xprt); 307 if (xprt->xp_sock != -1) 308 (void)close(xprt->xp_sock); 309 xprt->xp_sock = -1; 310 if (xprt->xp_port != 0) { 311 /* a rendezvouser socket */ 312 xprt->xp_port = 0; 313 } else { 314 /* an actual connection socket */ 315 XDR_DESTROY(&(cd->xdrs)); 316 } 317 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 318 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 319 } 320 321 /* 322 * All read operations timeout after 35 seconds. 323 * A timeout is fatal for the connection. 324 */ 325 static struct timespec wait_per_try = { 35, 0 }; 326 327 /* 328 * reads data from the tcp conection. 329 * any error is fatal and the connection is closed. 330 * (And a read of zero bytes is a half closed stream => error.) 331 */ 332 static int 333 readtcp(SVCXPRT *xprt, caddr_t buf, int len) 334 { 335 int sock = xprt->xp_sock; 336 int nready; 337 struct timespec start, after, duration, delta; 338 struct pollfd pfd[1]; 339 340 /* 341 * All read operations timeout after 35 seconds. 342 * A timeout is fatal for the connection. 343 */ 344 delta = wait_per_try; 345 WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); 346 pfd[0].fd = sock; 347 pfd[0].events = POLLIN; 348 do { 349 nready = ppoll(pfd, 1, &delta, NULL); 350 switch (nready) { 351 case -1: 352 if (errno != EINTR) 353 goto fatal_err; 354 WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); 355 timespecsub(&after, &start, &duration); 356 timespecsub(&wait_per_try, &duration, &delta); 357 if (delta.tv_sec < 0 || !timespecisset(&delta)) 358 goto fatal_err; 359 continue; 360 case 0: 361 goto fatal_err; 362 } 363 } while (pfd[0].revents == 0); 364 if ((len = read(sock, buf, len)) > 0) 365 return (len); 366 fatal_err: 367 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 368 return (-1); 369 } 370 371 /* 372 * writes data to the tcp connection. 373 * Any error is fatal and the connection is closed. 374 */ 375 static int 376 writetcp(SVCXPRT *xprt, caddr_t buf, int len) 377 { 378 int i, cnt; 379 380 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 381 if ((i = write(xprt->xp_sock, buf, cnt)) == -1) { 382 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 383 XPRT_DIED; 384 return (-1); 385 } 386 } 387 return (len); 388 } 389 390 static enum xprt_stat 391 svctcp_stat(SVCXPRT *xprt) 392 { 393 struct tcp_conn *cd = 394 (struct tcp_conn *)(xprt->xp_p1); 395 396 if (cd->strm_stat == XPRT_DIED) 397 return (XPRT_DIED); 398 if (! xdrrec_eof(&(cd->xdrs))) 399 return (XPRT_MOREREQS); 400 return (XPRT_IDLE); 401 } 402 403 static bool_t 404 svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg) 405 { 406 struct tcp_conn *cd = 407 (struct tcp_conn *)(xprt->xp_p1); 408 XDR *xdrs = &(cd->xdrs); 409 410 xdrs->x_op = XDR_DECODE; 411 (void)xdrrec_skiprecord(xdrs); 412 if (xdr_callmsg(xdrs, msg)) { 413 cd->x_id = msg->rm_xid; 414 return (TRUE); 415 } 416 cd->strm_stat = XPRT_DIED; /* XXX */ 417 return (FALSE); 418 } 419 420 static bool_t 421 svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 422 { 423 424 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 425 } 426 427 static bool_t 428 svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 429 { 430 XDR *xdrs = 431 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 432 433 xdrs->x_op = XDR_FREE; 434 return ((*xdr_args)(xdrs, args_ptr)); 435 } 436 437 static bool_t 438 svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg) 439 { 440 struct tcp_conn *cd = 441 (struct tcp_conn *)(xprt->xp_p1); 442 XDR *xdrs = &(cd->xdrs); 443 bool_t stat; 444 445 xdrs->x_op = XDR_ENCODE; 446 msg->rm_xid = cd->x_id; 447 stat = xdr_replymsg(xdrs, msg); 448 (void)xdrrec_endofrecord(xdrs, TRUE); 449 return (stat); 450 } 451