1 /* $OpenBSD: svc_tcp.c,v 1.33 2014/10/25 03:18:58 lteo 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 perror("svctcp_.c - udp socket creation problem"); 139 return (NULL); 140 } 141 madesock = TRUE; 142 } 143 memset(&addr, 0, sizeof (addr)); 144 addr.sin_len = sizeof(struct sockaddr_in); 145 addr.sin_family = AF_INET; 146 if (bindresvport(sock, &addr)) { 147 addr.sin_port = 0; 148 (void)bind(sock, (struct sockaddr *)&addr, len); 149 } 150 if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || 151 (listen(sock, 2) != 0)) { 152 perror("svctcp_.c - cannot getsockname or listen"); 153 if (madesock) 154 (void)close(sock); 155 return (NULL); 156 } 157 r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); 158 if (r == NULL) { 159 (void)fprintf(stderr, "svctcp_create: out of memory\n"); 160 if (madesock) 161 (void)close(sock); 162 return (NULL); 163 } 164 r->sendsize = sendsize; 165 r->recvsize = recvsize; 166 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 167 if (xprt == NULL) { 168 (void)fprintf(stderr, "svctcp_create: out of memory\n"); 169 if (madesock) 170 (void)close(sock); 171 free(r); 172 return (NULL); 173 } 174 xprt->xp_p2 = NULL; 175 xprt->xp_p1 = (caddr_t)r; 176 xprt->xp_verf = _null_auth; 177 xprt->xp_ops = &svctcp_rendezvous_op; 178 xprt->xp_port = ntohs(addr.sin_port); 179 xprt->xp_sock = sock; 180 if (__xprt_register(xprt) == 0) { 181 if (madesock) 182 (void)close(sock); 183 free(r); 184 free(xprt); 185 return (NULL); 186 } 187 return (xprt); 188 } 189 190 /* 191 * Like svtcp_create(), except the routine takes any *open* UNIX file 192 * descriptor as its first input. 193 */ 194 SVCXPRT * 195 svcfd_create(int fd, u_int sendsize, u_int recvsize) 196 { 197 198 return (makefd_xprt(fd, sendsize, recvsize)); 199 } 200 201 static SVCXPRT * 202 makefd_xprt(int fd, u_int sendsize, u_int recvsize) 203 { 204 SVCXPRT *xprt; 205 struct tcp_conn *cd; 206 207 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 208 if (xprt == NULL) { 209 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 210 goto done; 211 } 212 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 213 if (cd == NULL) { 214 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 215 mem_free((char *) xprt, sizeof(SVCXPRT)); 216 xprt = NULL; 217 goto done; 218 } 219 cd->strm_stat = XPRT_IDLE; 220 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 221 (caddr_t)xprt, (int(*)(caddr_t, caddr_t, int))readtcp, 222 (int(*)(caddr_t, caddr_t, int))writetcp); 223 xprt->xp_p2 = NULL; 224 xprt->xp_p1 = (caddr_t)cd; 225 xprt->xp_verf.oa_base = cd->verf_body; 226 xprt->xp_addrlen = 0; 227 xprt->xp_ops = &svctcp_op; /* truely deals with calls */ 228 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 229 xprt->xp_sock = fd; 230 if (__xprt_register(xprt) == 0) { 231 free(xprt); 232 free(cd); 233 return (NULL); 234 } 235 done: 236 return (xprt); 237 } 238 239 /* ARGSUSED */ 240 static bool_t 241 rendezvous_request(SVCXPRT *xprt, struct rpc_msg *ignored) 242 { 243 int sock; 244 struct tcp_rendezvous *r; 245 struct sockaddr_in addr; 246 socklen_t len; 247 248 r = (struct tcp_rendezvous *)xprt->xp_p1; 249 again: 250 len = sizeof(struct sockaddr_in); 251 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, 252 &len)) < 0) { 253 if (errno == EINTR || errno == EWOULDBLOCK || 254 errno == ECONNABORTED) 255 goto again; 256 return (FALSE); 257 } 258 259 #ifdef IP_OPTIONS 260 { 261 struct ipoption opts; 262 socklen_t optsize = sizeof(opts); 263 int i; 264 265 if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts, 266 &optsize) && optsize != 0) { 267 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 268 optsize; ) { 269 u_char c = (u_char)opts.ipopt_list[i]; 270 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 271 close(sock); 272 return (FALSE); 273 } 274 if (c == IPOPT_EOL) 275 break; 276 i += (c == IPOPT_NOP) ? 1 : 277 (u_char)opts.ipopt_list[i+1]; 278 } 279 } 280 } 281 #endif 282 283 /* 284 * XXX careful for ftp bounce attacks. If discovered, close the 285 * socket and look for another connection. 286 */ 287 if (addr.sin_port == htons(20)) { 288 close(sock); 289 return (FALSE); 290 } 291 292 /* 293 * make a new transporter (re-uses xprt) 294 */ 295 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 296 xprt->xp_raddr = addr; 297 xprt->xp_addrlen = len; 298 return (FALSE); /* there is never an rpc msg to be processed */ 299 } 300 301 /* ARGSUSED */ 302 static enum xprt_stat 303 rendezvous_stat(SVCXPRT *xprt) 304 { 305 306 return (XPRT_IDLE); 307 } 308 309 static void 310 svctcp_destroy(SVCXPRT *xprt) 311 { 312 struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 313 314 xprt_unregister(xprt); 315 if (xprt->xp_sock != -1) 316 (void)close(xprt->xp_sock); 317 xprt->xp_sock = -1; 318 if (xprt->xp_port != 0) { 319 /* a rendezvouser socket */ 320 xprt->xp_port = 0; 321 } else { 322 /* an actual connection socket */ 323 XDR_DESTROY(&(cd->xdrs)); 324 } 325 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 326 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 327 } 328 329 /* 330 * All read operations timeout after 35 seconds. 331 * A timeout is fatal for the connection. 332 */ 333 static struct timeval wait_per_try = { 35, 0 }; 334 335 /* 336 * reads data from the tcp conection. 337 * any error is fatal and the connection is closed. 338 * (And a read of zero bytes is a half closed stream => error.) 339 */ 340 static int 341 readtcp(SVCXPRT *xprt, caddr_t buf, int len) 342 { 343 int sock = xprt->xp_sock; 344 int delta, nready; 345 struct timeval start; 346 struct timeval tmp1, tmp2; 347 struct pollfd pfd[1]; 348 349 /* 350 * All read operations timeout after 35 seconds. 351 * A timeout is fatal for the connection. 352 */ 353 delta = wait_per_try.tv_sec * 1000; 354 gettimeofday(&start, NULL); 355 pfd[0].fd = sock; 356 pfd[0].events = POLLIN; 357 do { 358 nready = poll(pfd, 1, delta); 359 switch (nready) { 360 case -1: 361 if (errno != EINTR) 362 goto fatal_err; 363 gettimeofday(&tmp1, NULL); 364 timersub(&tmp1, &start, &tmp2); 365 timersub(&wait_per_try, &tmp2, &tmp1); 366 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 367 goto fatal_err; 368 delta = tmp1.tv_sec * 1000 + tmp1.tv_usec / 1000; 369 continue; 370 case 0: 371 goto fatal_err; 372 } 373 } while (pfd[0].revents == 0); 374 if ((len = read(sock, buf, len)) > 0) 375 return (len); 376 fatal_err: 377 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 378 return (-1); 379 } 380 381 /* 382 * writes data to the tcp connection. 383 * Any error is fatal and the connection is closed. 384 */ 385 static int 386 writetcp(SVCXPRT *xprt, caddr_t buf, int len) 387 { 388 int i, cnt; 389 390 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 391 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 392 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 393 XPRT_DIED; 394 return (-1); 395 } 396 } 397 return (len); 398 } 399 400 static enum xprt_stat 401 svctcp_stat(SVCXPRT *xprt) 402 { 403 struct tcp_conn *cd = 404 (struct tcp_conn *)(xprt->xp_p1); 405 406 if (cd->strm_stat == XPRT_DIED) 407 return (XPRT_DIED); 408 if (! xdrrec_eof(&(cd->xdrs))) 409 return (XPRT_MOREREQS); 410 return (XPRT_IDLE); 411 } 412 413 static bool_t 414 svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg) 415 { 416 struct tcp_conn *cd = 417 (struct tcp_conn *)(xprt->xp_p1); 418 XDR *xdrs = &(cd->xdrs); 419 420 xdrs->x_op = XDR_DECODE; 421 (void)xdrrec_skiprecord(xdrs); 422 if (xdr_callmsg(xdrs, msg)) { 423 cd->x_id = msg->rm_xid; 424 return (TRUE); 425 } 426 cd->strm_stat = XPRT_DIED; /* XXX */ 427 return (FALSE); 428 } 429 430 static bool_t 431 svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 432 { 433 434 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 435 } 436 437 static bool_t 438 svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 439 { 440 XDR *xdrs = 441 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 442 443 xdrs->x_op = XDR_FREE; 444 return ((*xdr_args)(xdrs, args_ptr)); 445 } 446 447 static bool_t 448 svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg) 449 { 450 struct tcp_conn *cd = 451 (struct tcp_conn *)(xprt->xp_p1); 452 XDR *xdrs = &(cd->xdrs); 453 bool_t stat; 454 455 xdrs->x_op = XDR_ENCODE; 456 msg->rm_xid = cd->x_id; 457 stat = xdr_replymsg(xdrs, msg); 458 (void)xdrrec_endofrecord(xdrs, TRUE); 459 return (stat); 460 } 461