1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char *rcsid = "$OpenBSD: svc_tcp.c,v 1.20 2001/09/15 13:51:01 deraadt Exp $"; 32 #endif /* LIBC_SCCS and not lint */ 33 34 /* 35 * svc_tcp.c, Server side for TCP/IP based RPC. 36 * 37 * Copyright (C) 1984, Sun Microsystems, Inc. 38 * 39 * Actually implements two flavors of transporter - 40 * a tcp rendezvouser (a listner and connection establisher) 41 * and a record/tcp stream. 42 */ 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <rpc/rpc.h> 49 #include <sys/socket.h> 50 #include <errno.h> 51 52 #include <netinet/in_systm.h> 53 #include <netinet/in.h> 54 #include <netinet/ip.h> 55 #include <netinet/ip_var.h> 56 57 /* 58 * Ops vector for TCP/IP based rpc service handle 59 */ 60 static bool_t svctcp_recv(); 61 static enum xprt_stat svctcp_stat(); 62 static bool_t svctcp_getargs(); 63 static bool_t svctcp_reply(); 64 static bool_t svctcp_freeargs(); 65 static void svctcp_destroy(); 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(); 80 static enum xprt_stat rendezvous_stat(); 81 82 static struct xp_ops svctcp_rendezvous_op = { 83 rendezvous_request, 84 rendezvous_stat, 85 (bool_t (*)())abort, 86 (bool_t (*)())abort, 87 (bool_t (*)())abort, 88 svctcp_destroy 89 }; 90 91 static int readtcp(), writetcp(); 92 static SVCXPRT *makefd_xprt(); 93 94 struct tcp_rendezvous { /* kept in xprt->xp_p1 */ 95 u_int sendsize; 96 u_int recvsize; 97 }; 98 99 struct tcp_conn { /* kept in xprt->xp_p1 */ 100 enum xprt_stat strm_stat; 101 u_long x_id; 102 XDR xdrs; 103 char verf_body[MAX_AUTH_BYTES]; 104 }; 105 106 /* 107 * Usage: 108 * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); 109 * 110 * Creates, registers, and returns a (rpc) tcp based transporter. 111 * Once *xprt is initialized, it is registered as a transporter 112 * see (svc.h, xprt_register). This routine returns 113 * a NULL if a problem occurred. 114 * 115 * If sock<0 then a socket is created, else sock is used. 116 * If the socket, sock is not bound to a port then svctcp_create 117 * binds it to an arbitrary port. The routine then starts a tcp 118 * listener on the socket's associated port. In any (successful) case, 119 * xprt->xp_sock is the registered socket number and xprt->xp_port is the 120 * associated port number. 121 * 122 * Since tcp streams do buffered io similar to stdio, the caller can specify 123 * how big the send and receive buffers are via the second and third parms; 124 * 0 => use the system default. 125 */ 126 SVCXPRT * 127 svctcp_create(sock, sendsize, recvsize) 128 int sock; 129 u_int sendsize; 130 u_int recvsize; 131 { 132 bool_t madesock = FALSE; 133 SVCXPRT *xprt; 134 struct tcp_rendezvous *r; 135 struct sockaddr_in addr; 136 int len = sizeof(struct sockaddr_in); 137 138 if (sock == RPC_ANYSOCK) { 139 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 140 perror("svctcp_.c - udp socket creation problem"); 141 return ((SVCXPRT *)NULL); 142 } 143 madesock = TRUE; 144 } 145 memset(&addr, 0, sizeof (addr)); 146 addr.sin_len = sizeof(struct sockaddr_in); 147 addr.sin_family = AF_INET; 148 if (bindresvport(sock, &addr)) { 149 addr.sin_port = 0; 150 (void)bind(sock, (struct sockaddr *)&addr, len); 151 } 152 if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || 153 (listen(sock, 2) != 0)) { 154 perror("svctcp_.c - cannot getsockname or listen"); 155 if (madesock) 156 (void)close(sock); 157 return ((SVCXPRT *)NULL); 158 } 159 r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); 160 if (r == NULL) { 161 (void)fprintf(stderr, "svctcp_create: out of memory\n"); 162 if (madesock) 163 (void)close(sock); 164 return (NULL); 165 } 166 r->sendsize = sendsize; 167 r->recvsize = recvsize; 168 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 169 if (xprt == NULL) { 170 (void)fprintf(stderr, "svctcp_create: out of memory\n"); 171 if (madesock) 172 (void)close(sock); 173 free(r); 174 return (NULL); 175 } 176 xprt->xp_p2 = NULL; 177 xprt->xp_p1 = (caddr_t)r; 178 xprt->xp_verf = _null_auth; 179 xprt->xp_ops = &svctcp_rendezvous_op; 180 xprt->xp_port = ntohs(addr.sin_port); 181 xprt->xp_sock = sock; 182 if (__xprt_register(xprt) == 0) { 183 if (madesock) 184 (void)close(sock); 185 free(r); 186 free(xprt); 187 return (NULL); 188 } 189 return (xprt); 190 } 191 192 /* 193 * Like svtcp_create(), except the routine takes any *open* UNIX file 194 * descriptor as its first input. 195 */ 196 SVCXPRT * 197 svcfd_create(fd, sendsize, recvsize) 198 int fd; 199 u_int sendsize; 200 u_int recvsize; 201 { 202 203 return (makefd_xprt(fd, sendsize, recvsize)); 204 } 205 206 static SVCXPRT * 207 makefd_xprt(fd, sendsize, recvsize) 208 int fd; 209 u_int sendsize; 210 u_int recvsize; 211 { 212 SVCXPRT *xprt; 213 struct tcp_conn *cd; 214 215 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 216 if (xprt == (SVCXPRT *)NULL) { 217 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 218 goto done; 219 } 220 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 221 if (cd == (struct tcp_conn *)NULL) { 222 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 223 mem_free((char *) xprt, sizeof(SVCXPRT)); 224 xprt = (SVCXPRT *)NULL; 225 goto done; 226 } 227 cd->strm_stat = XPRT_IDLE; 228 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 229 (caddr_t)xprt, readtcp, writetcp); 230 xprt->xp_p2 = NULL; 231 xprt->xp_p1 = (caddr_t)cd; 232 xprt->xp_verf.oa_base = cd->verf_body; 233 xprt->xp_addrlen = 0; 234 xprt->xp_ops = &svctcp_op; /* truely deals with calls */ 235 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 236 xprt->xp_sock = fd; 237 if (__xprt_register(xprt) == 0) { 238 free(xprt); 239 free(cd); 240 return (NULL); 241 } 242 done: 243 return (xprt); 244 } 245 246 static bool_t 247 rendezvous_request(xprt) 248 SVCXPRT *xprt; 249 { 250 int sock; 251 struct tcp_rendezvous *r; 252 struct sockaddr_in addr; 253 int len; 254 255 r = (struct tcp_rendezvous *)xprt->xp_p1; 256 again: 257 len = sizeof(struct sockaddr_in); 258 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, 259 &len)) < 0) { 260 if (errno == EINTR) 261 goto again; 262 return (FALSE); 263 } 264 265 #ifdef IP_OPTIONS 266 { 267 struct ipoption opts; 268 int optsize = sizeof(opts), i; 269 270 if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts, 271 &optsize) && optsize != 0) { 272 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 273 optsize; ) { 274 u_char c = (u_char)opts.ipopt_list[i]; 275 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 276 close(sock); 277 return (FALSE); 278 } 279 if (c == IPOPT_EOL) 280 break; 281 i += (c == IPOPT_NOP) ? 1 : 282 (u_char)opts.ipopt_list[i+1]; 283 } 284 } 285 } 286 #endif 287 288 /* 289 * XXX careful for ftp bounce attacks. If discovered, close the 290 * socket and look for another connection. 291 */ 292 if (addr.sin_port == htons(20)) { 293 close(sock); 294 return (FALSE); 295 } 296 297 /* 298 * make a new transporter (re-uses xprt) 299 */ 300 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 301 xprt->xp_raddr = addr; 302 xprt->xp_addrlen = len; 303 return (FALSE); /* there is never an rpc msg to be processed */ 304 } 305 306 static enum xprt_stat 307 rendezvous_stat() 308 { 309 310 return (XPRT_IDLE); 311 } 312 313 static void 314 svctcp_destroy(xprt) 315 SVCXPRT *xprt; 316 { 317 struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 318 319 xprt_unregister(xprt); 320 if (xprt->xp_sock != -1) 321 (void)close(xprt->xp_sock); 322 xprt->xp_sock = -1; 323 if (xprt->xp_port != 0) { 324 /* a rendezvouser socket */ 325 xprt->xp_port = 0; 326 } else { 327 /* an actual connection socket */ 328 XDR_DESTROY(&(cd->xdrs)); 329 } 330 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 331 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 332 } 333 334 /* 335 * All read operations timeout after 35 seconds. 336 * A timeout is fatal for the connection. 337 */ 338 static struct timeval wait_per_try = { 35, 0 }; 339 340 /* 341 * reads data from the tcp conection. 342 * any error is fatal and the connection is closed. 343 * (And a read of zero bytes is a half closed stream => error.) 344 */ 345 static int 346 readtcp(xprt, buf, len) 347 SVCXPRT *xprt; 348 caddr_t buf; 349 int len; 350 { 351 int sock = xprt->xp_sock; 352 struct timeval start, delta; 353 struct timeval tmp1, tmp2; 354 fd_set *fds = NULL; 355 int prevbytes = 0, bytes; 356 extern int __svc_fdsetsize; 357 extern fd_set *__svc_fdset; 358 359 delta = wait_per_try; 360 gettimeofday(&start, NULL); 361 do { 362 bytes = howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask); 363 if (bytes != prevbytes) { 364 if (fds) 365 free(fds); 366 fds = (fd_set *)malloc(bytes); 367 prevbytes = bytes; 368 } 369 if (fds == NULL) 370 goto fatal_err; 371 memcpy(fds, __svc_fdset, bytes); 372 373 FD_SET(sock, fds); 374 switch (select(svc_maxfd+1, fds, NULL, NULL, &delta)) { 375 case -1: 376 if (errno != EINTR) 377 goto fatal_err; 378 gettimeofday(&tmp1, NULL); 379 timersub(&tmp1, &start, &tmp2); 380 timersub(&wait_per_try, &tmp2, &tmp1); 381 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 382 goto fatal_err; 383 delta = tmp1; 384 continue; 385 case 0: 386 goto fatal_err; 387 default: 388 if (!FD_ISSET(sock, fds)) { 389 svc_getreqset2(fds, svc_maxfd+1); 390 gettimeofday(&tmp1, NULL); 391 timersub(&tmp1, &start, &tmp2); 392 timersub(&wait_per_try, &tmp2, &tmp1); 393 if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) 394 goto fatal_err; 395 delta = tmp1; 396 continue; 397 } 398 } 399 } while (!FD_ISSET(sock, fds)); 400 if ((len = read(sock, buf, len)) > 0) { 401 if (fds) 402 free(fds); 403 return (len); 404 } 405 fatal_err: 406 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 407 if (fds) 408 free(fds); 409 return (-1); 410 } 411 412 /* 413 * writes data to the tcp connection. 414 * Any error is fatal and the connection is closed. 415 */ 416 static int 417 writetcp(xprt, buf, len) 418 SVCXPRT *xprt; 419 caddr_t buf; 420 int len; 421 { 422 int i, cnt; 423 424 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 425 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 426 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 427 XPRT_DIED; 428 return (-1); 429 } 430 } 431 return (len); 432 } 433 434 static enum xprt_stat 435 svctcp_stat(xprt) 436 SVCXPRT *xprt; 437 { 438 struct tcp_conn *cd = 439 (struct tcp_conn *)(xprt->xp_p1); 440 441 if (cd->strm_stat == XPRT_DIED) 442 return (XPRT_DIED); 443 if (! xdrrec_eof(&(cd->xdrs))) 444 return (XPRT_MOREREQS); 445 return (XPRT_IDLE); 446 } 447 448 static bool_t 449 svctcp_recv(xprt, msg) 450 SVCXPRT *xprt; 451 struct rpc_msg *msg; 452 { 453 struct tcp_conn *cd = 454 (struct tcp_conn *)(xprt->xp_p1); 455 XDR *xdrs = &(cd->xdrs); 456 457 xdrs->x_op = XDR_DECODE; 458 (void)xdrrec_skiprecord(xdrs); 459 if (xdr_callmsg(xdrs, msg)) { 460 cd->x_id = msg->rm_xid; 461 return (TRUE); 462 } 463 cd->strm_stat = XPRT_DIED; /* XXX */ 464 return (FALSE); 465 } 466 467 static bool_t 468 svctcp_getargs(xprt, xdr_args, args_ptr) 469 SVCXPRT *xprt; 470 xdrproc_t xdr_args; 471 caddr_t args_ptr; 472 { 473 474 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 475 } 476 477 static bool_t 478 svctcp_freeargs(xprt, xdr_args, args_ptr) 479 SVCXPRT *xprt; 480 xdrproc_t xdr_args; 481 caddr_t args_ptr; 482 { 483 XDR *xdrs = 484 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 485 486 xdrs->x_op = XDR_FREE; 487 return ((*xdr_args)(xdrs, args_ptr)); 488 } 489 490 static bool_t 491 svctcp_reply(xprt, msg) 492 SVCXPRT *xprt; 493 struct rpc_msg *msg; 494 { 495 struct tcp_conn *cd = 496 (struct tcp_conn *)(xprt->xp_p1); 497 XDR *xdrs = &(cd->xdrs); 498 bool_t stat; 499 500 xdrs->x_op = XDR_ENCODE; 501 msg->rm_xid = cd->x_id; 502 stat = xdr_replymsg(xdrs, msg); 503 (void)xdrrec_endofrecord(xdrs, TRUE); 504 return (stat); 505 } 506