1 /* $OpenBSD: svc_tcp.c,v 1.28 2006/04/02 00:36:05 deraadt Exp $ */ 2 /* 3 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 4 * unrestricted use provided that this legend is included on all tape 5 * media and as a part of the software program in whole or part. Users 6 * may copy or modify Sun RPC without charge, but are not authorized 7 * to license or distribute it to anyone else except as part of a product or 8 * program developed by the user. 9 * 10 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 11 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 12 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 13 * 14 * Sun RPC is provided with no support and without any obligation on the 15 * part of Sun Microsystems, Inc. to assist in its use, correction, 16 * modification or enhancement. 17 * 18 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 19 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 20 * OR ANY PART THEREOF. 21 * 22 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 23 * or profits or other special, indirect and consequential damages, even if 24 * Sun has been advised of the possibility of such damages. 25 * 26 * Sun Microsystems, Inc. 27 * 2550 Garcia Avenue 28 * Mountain View, California 94043 29 */ 30 31 /* 32 * svc_tcp.c, Server side for TCP/IP based RPC. 33 * 34 * Copyright (C) 1984, Sun Microsystems, Inc. 35 * 36 * Actually implements two flavors of transporter - 37 * a tcp rendezvouser (a listner and connection establisher) 38 * and a record/tcp stream. 39 */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <rpc/rpc.h> 46 #include <sys/socket.h> 47 #include <errno.h> 48 49 #include <netinet/in_systm.h> 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) 254 goto again; 255 return (FALSE); 256 } 257 258 #ifdef IP_OPTIONS 259 { 260 struct ipoption opts; 261 socklen_t optsize = sizeof(opts); 262 int i; 263 264 if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts, 265 &optsize) && optsize != 0) { 266 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 267 optsize; ) { 268 u_char c = (u_char)opts.ipopt_list[i]; 269 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 270 close(sock); 271 return (FALSE); 272 } 273 if (c == IPOPT_EOL) 274 break; 275 i += (c == IPOPT_NOP) ? 1 : 276 (u_char)opts.ipopt_list[i+1]; 277 } 278 } 279 } 280 #endif 281 282 /* 283 * XXX careful for ftp bounce attacks. If discovered, close the 284 * socket and look for another connection. 285 */ 286 if (addr.sin_port == htons(20)) { 287 close(sock); 288 return (FALSE); 289 } 290 291 /* 292 * make a new transporter (re-uses xprt) 293 */ 294 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 295 xprt->xp_raddr = addr; 296 xprt->xp_addrlen = len; 297 return (FALSE); /* there is never an rpc msg to be processed */ 298 } 299 300 /* ARGSUSED */ 301 static enum xprt_stat 302 rendezvous_stat(SVCXPRT *xprt) 303 { 304 305 return (XPRT_IDLE); 306 } 307 308 static void 309 svctcp_destroy(SVCXPRT *xprt) 310 { 311 struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 312 313 xprt_unregister(xprt); 314 if (xprt->xp_sock != -1) 315 (void)close(xprt->xp_sock); 316 xprt->xp_sock = -1; 317 if (xprt->xp_port != 0) { 318 /* a rendezvouser socket */ 319 xprt->xp_port = 0; 320 } else { 321 /* an actual connection socket */ 322 XDR_DESTROY(&(cd->xdrs)); 323 } 324 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 325 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 326 } 327 328 /* 329 * All read operations timeout after 35 seconds. 330 * A timeout is fatal for the connection. 331 */ 332 static struct timeval wait_per_try = { 35, 0 }; 333 334 /* 335 * reads data from the tcp conection. 336 * any error is fatal and the connection is closed. 337 * (And a read of zero bytes is a half closed stream => error.) 338 */ 339 static int 340 readtcp(SVCXPRT *xprt, caddr_t buf, int len) 341 { 342 int sock = xprt->xp_sock; 343 int delta, nready; 344 struct timeval start; 345 struct timeval tmp1, tmp2; 346 struct pollfd *pfd = NULL; 347 348 pfd = (struct pollfd *)malloc(sizeof(*pfd) * (svc_max_pollfd + 1)); 349 if (pfd == NULL) 350 goto fatal_err; 351 pfd[0].fd = sock; 352 pfd[0].events = POLLIN; 353 pfd[0].revents = 0; 354 memcpy(&pfd[1], svc_pollfd, (sizeof(*pfd) * svc_max_pollfd)); 355 356 /* 357 * All read operations timeout after 35 seconds. 358 * A timeout is fatal for the connection. 359 */ 360 delta = wait_per_try.tv_sec * 1000; 361 gettimeofday(&start, NULL); 362 do { 363 nready = poll(pfd, svc_max_pollfd + 1, delta); 364 switch (nready) { 365 case -1: 366 if (errno != EINTR) 367 goto fatal_err; 368 gettimeofday(&tmp1, NULL); 369 timersub(&tmp1, &start, &tmp2); 370 timersub(&wait_per_try, &tmp2, &tmp1); 371 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 372 goto fatal_err; 373 delta = tmp1.tv_sec * 1000 + tmp1.tv_usec / 1000; 374 continue; 375 case 0: 376 goto fatal_err; 377 default: 378 if (pfd[0].revents == 0) { 379 svc_getreq_poll(&pfd[1], nready); 380 gettimeofday(&tmp1, NULL); 381 timersub(&tmp1, &start, &tmp2); 382 timersub(&wait_per_try, &tmp2, &tmp1); 383 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 384 goto fatal_err; 385 delta = tmp1.tv_sec * 1000 + tmp1.tv_usec / 1000; 386 continue; 387 } 388 } 389 } while (pfd[0].revents == 0); 390 if ((len = read(sock, buf, len)) > 0) { 391 if (pfd) 392 free(pfd); 393 return (len); 394 } 395 fatal_err: 396 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 397 if (pfd) 398 free(pfd); 399 return (-1); 400 } 401 402 /* 403 * writes data to the tcp connection. 404 * Any error is fatal and the connection is closed. 405 */ 406 static int 407 writetcp(SVCXPRT *xprt, caddr_t buf, int len) 408 { 409 int i, cnt; 410 411 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 412 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 413 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 414 XPRT_DIED; 415 return (-1); 416 } 417 } 418 return (len); 419 } 420 421 static enum xprt_stat 422 svctcp_stat(SVCXPRT *xprt) 423 { 424 struct tcp_conn *cd = 425 (struct tcp_conn *)(xprt->xp_p1); 426 427 if (cd->strm_stat == XPRT_DIED) 428 return (XPRT_DIED); 429 if (! xdrrec_eof(&(cd->xdrs))) 430 return (XPRT_MOREREQS); 431 return (XPRT_IDLE); 432 } 433 434 static bool_t 435 svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg) 436 { 437 struct tcp_conn *cd = 438 (struct tcp_conn *)(xprt->xp_p1); 439 XDR *xdrs = &(cd->xdrs); 440 441 xdrs->x_op = XDR_DECODE; 442 (void)xdrrec_skiprecord(xdrs); 443 if (xdr_callmsg(xdrs, msg)) { 444 cd->x_id = msg->rm_xid; 445 return (TRUE); 446 } 447 cd->strm_stat = XPRT_DIED; /* XXX */ 448 return (FALSE); 449 } 450 451 static bool_t 452 svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 453 { 454 455 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 456 } 457 458 static bool_t 459 svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 460 { 461 XDR *xdrs = 462 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 463 464 xdrs->x_op = XDR_FREE; 465 return ((*xdr_args)(xdrs, args_ptr)); 466 } 467 468 static bool_t 469 svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg) 470 { 471 struct tcp_conn *cd = 472 (struct tcp_conn *)(xprt->xp_p1); 473 XDR *xdrs = &(cd->xdrs); 474 bool_t stat; 475 476 xdrs->x_op = XDR_ENCODE; 477 msg->rm_xid = cd->x_id; 478 stat = xdr_replymsg(xdrs, msg); 479 (void)xdrrec_endofrecord(xdrs, TRUE); 480 return (stat); 481 } 482