1 /* $OpenBSD: svc_tcp.c,v 1.37 2015/11/01 03:45:29 guenther 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)) < 0) 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)) { 145 addr.sin_port = 0; 146 (void)bind(sock, (struct sockaddr *)&addr, len); 147 } 148 if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || 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)) < 0) { 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, (char *)&opts, 258 &optsize) && optsize != 0) { 259 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 260 optsize; ) { 261 u_char c = (u_char)opts.ipopt_list[i]; 262 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 263 close(sock); 264 return (FALSE); 265 } 266 if (c == IPOPT_EOL) 267 break; 268 i += (c == IPOPT_NOP) ? 1 : 269 (u_char)opts.ipopt_list[i+1]; 270 } 271 } 272 } 273 #endif 274 275 /* 276 * XXX careful for ftp bounce attacks. If discovered, close the 277 * socket and look for another connection. 278 */ 279 if (addr.sin_port == htons(20)) { 280 close(sock); 281 return (FALSE); 282 } 283 284 /* 285 * make a new transporter (re-uses xprt) 286 */ 287 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 288 xprt->xp_raddr = addr; 289 xprt->xp_addrlen = len; 290 return (FALSE); /* there is never an rpc msg to be processed */ 291 } 292 293 static enum xprt_stat 294 rendezvous_stat(SVCXPRT *xprt) 295 { 296 297 return (XPRT_IDLE); 298 } 299 300 static void 301 svctcp_destroy(SVCXPRT *xprt) 302 { 303 struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 304 305 xprt_unregister(xprt); 306 if (xprt->xp_sock != -1) 307 (void)close(xprt->xp_sock); 308 xprt->xp_sock = -1; 309 if (xprt->xp_port != 0) { 310 /* a rendezvouser socket */ 311 xprt->xp_port = 0; 312 } else { 313 /* an actual connection socket */ 314 XDR_DESTROY(&(cd->xdrs)); 315 } 316 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 317 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 318 } 319 320 /* 321 * All read operations timeout after 35 seconds. 322 * A timeout is fatal for the connection. 323 */ 324 static struct timeval wait_per_try = { 35, 0 }; 325 326 /* 327 * reads data from the tcp conection. 328 * any error is fatal and the connection is closed. 329 * (And a read of zero bytes is a half closed stream => error.) 330 */ 331 static int 332 readtcp(SVCXPRT *xprt, caddr_t buf, int len) 333 { 334 int sock = xprt->xp_sock; 335 int delta, nready; 336 struct timeval start; 337 struct timeval tmp1, tmp2; 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.tv_sec * 1000; 345 gettimeofday(&start, NULL); 346 pfd[0].fd = sock; 347 pfd[0].events = POLLIN; 348 do { 349 nready = poll(pfd, 1, delta); 350 switch (nready) { 351 case -1: 352 if (errno != EINTR) 353 goto fatal_err; 354 gettimeofday(&tmp1, NULL); 355 timersub(&tmp1, &start, &tmp2); 356 timersub(&wait_per_try, &tmp2, &tmp1); 357 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 358 goto fatal_err; 359 delta = tmp1.tv_sec * 1000 + tmp1.tv_usec / 1000; 360 continue; 361 case 0: 362 goto fatal_err; 363 } 364 } while (pfd[0].revents == 0); 365 if ((len = read(sock, buf, len)) > 0) 366 return (len); 367 fatal_err: 368 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 369 return (-1); 370 } 371 372 /* 373 * writes data to the tcp connection. 374 * Any error is fatal and the connection is closed. 375 */ 376 static int 377 writetcp(SVCXPRT *xprt, caddr_t buf, int len) 378 { 379 int i, cnt; 380 381 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 382 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 383 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 384 XPRT_DIED; 385 return (-1); 386 } 387 } 388 return (len); 389 } 390 391 static enum xprt_stat 392 svctcp_stat(SVCXPRT *xprt) 393 { 394 struct tcp_conn *cd = 395 (struct tcp_conn *)(xprt->xp_p1); 396 397 if (cd->strm_stat == XPRT_DIED) 398 return (XPRT_DIED); 399 if (! xdrrec_eof(&(cd->xdrs))) 400 return (XPRT_MOREREQS); 401 return (XPRT_IDLE); 402 } 403 404 static bool_t 405 svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg) 406 { 407 struct tcp_conn *cd = 408 (struct tcp_conn *)(xprt->xp_p1); 409 XDR *xdrs = &(cd->xdrs); 410 411 xdrs->x_op = XDR_DECODE; 412 (void)xdrrec_skiprecord(xdrs); 413 if (xdr_callmsg(xdrs, msg)) { 414 cd->x_id = msg->rm_xid; 415 return (TRUE); 416 } 417 cd->strm_stat = XPRT_DIED; /* XXX */ 418 return (FALSE); 419 } 420 421 static bool_t 422 svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 423 { 424 425 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 426 } 427 428 static bool_t 429 svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 430 { 431 XDR *xdrs = 432 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 433 434 xdrs->x_op = XDR_FREE; 435 return ((*xdr_args)(xdrs, args_ptr)); 436 } 437 438 static bool_t 439 svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg) 440 { 441 struct tcp_conn *cd = 442 (struct tcp_conn *)(xprt->xp_p1); 443 XDR *xdrs = &(cd->xdrs); 444 bool_t stat; 445 446 xdrs->x_op = XDR_ENCODE; 447 msg->rm_xid = cd->x_id; 448 stat = xdr_replymsg(xdrs, msg); 449 (void)xdrrec_endofrecord(xdrs, TRUE); 450 return (stat); 451 } 452