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