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.18 1998/05/22 04:23: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 register int sock; 129 u_int sendsize; 130 u_int recvsize; 131 { 132 bool_t madesock = FALSE; 133 register SVCXPRT *xprt; 134 register 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 xprt_register(xprt); 183 return (xprt); 184 } 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(fd, sendsize, recvsize) 192 int fd; 193 u_int sendsize; 194 u_int recvsize; 195 { 196 197 return (makefd_xprt(fd, sendsize, recvsize)); 198 } 199 200 static SVCXPRT * 201 makefd_xprt(fd, sendsize, recvsize) 202 int fd; 203 u_int sendsize; 204 u_int recvsize; 205 { 206 register SVCXPRT *xprt; 207 register struct tcp_conn *cd; 208 209 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 210 if (xprt == (SVCXPRT *)NULL) { 211 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 212 goto done; 213 } 214 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 215 if (cd == (struct tcp_conn *)NULL) { 216 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 217 mem_free((char *) xprt, sizeof(SVCXPRT)); 218 xprt = (SVCXPRT *)NULL; 219 goto done; 220 } 221 cd->strm_stat = XPRT_IDLE; 222 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 223 (caddr_t)xprt, readtcp, 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 xprt_register(xprt); 232 done: 233 return (xprt); 234 } 235 236 static bool_t 237 rendezvous_request(xprt) 238 register SVCXPRT *xprt; 239 { 240 int sock; 241 struct tcp_rendezvous *r; 242 struct sockaddr_in addr; 243 int len; 244 245 r = (struct tcp_rendezvous *)xprt->xp_p1; 246 again: 247 len = sizeof(struct sockaddr_in); 248 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, 249 &len)) < 0) { 250 if (errno == EINTR) 251 goto again; 252 return (FALSE); 253 } 254 255 #ifdef IP_OPTIONS 256 { 257 struct ipoption opts; 258 int optsize = sizeof(opts), i; 259 260 if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts, 261 &optsize) && optsize != 0) { 262 for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < 263 optsize; ) { 264 u_char c = (u_char)opts.ipopt_list[i]; 265 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 266 close(sock); 267 return (FALSE); 268 } 269 if (c == IPOPT_EOL) 270 break; 271 i += (c == IPOPT_NOP) ? 1 : 272 (u_char)opts.ipopt_list[i+1]; 273 } 274 } 275 } 276 #endif 277 278 /* 279 * XXX careful for ftp bounce attacks. If discovered, close the 280 * socket and look for another connection. 281 */ 282 if (addr.sin_port == htons(20)) { 283 close(sock); 284 return (FALSE); 285 } 286 287 /* 288 * make a new transporter (re-uses xprt) 289 */ 290 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 291 xprt->xp_raddr = addr; 292 xprt->xp_addrlen = len; 293 return (FALSE); /* there is never an rpc msg to be processed */ 294 } 295 296 static enum xprt_stat 297 rendezvous_stat() 298 { 299 300 return (XPRT_IDLE); 301 } 302 303 static void 304 svctcp_destroy(xprt) 305 register SVCXPRT *xprt; 306 { 307 register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 308 309 xprt_unregister(xprt); 310 if (xprt->xp_sock != -1) 311 (void)close(xprt->xp_sock); 312 xprt->xp_sock = -1; 313 if (xprt->xp_port != 0) { 314 /* a rendezvouser socket */ 315 xprt->xp_port = 0; 316 } else { 317 /* an actual connection socket */ 318 XDR_DESTROY(&(cd->xdrs)); 319 } 320 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 321 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 322 } 323 324 /* 325 * All read operations timeout after 35 seconds. 326 * A timeout is fatal for the connection. 327 */ 328 static struct timeval wait_per_try = { 35, 0 }; 329 330 /* 331 * reads data from the tcp conection. 332 * any error is fatal and the connection is closed. 333 * (And a read of zero bytes is a half closed stream => error.) 334 */ 335 static int 336 readtcp(xprt, buf, len) 337 register SVCXPRT *xprt; 338 caddr_t buf; 339 register int len; 340 { 341 register int sock = xprt->xp_sock; 342 struct timeval start, delta; 343 struct timeval tmp1, tmp2; 344 fd_set *fds = NULL; 345 int prevbytes = 0, bytes; 346 extern int __svc_fdsetsize; 347 extern fd_set *__svc_fdset; 348 349 delta = wait_per_try; 350 gettimeofday(&start, NULL); 351 do { 352 bytes = howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask); 353 if (bytes != prevbytes) { 354 if (fds) 355 free(fds); 356 fds = (fd_set *)malloc(bytes); 357 prevbytes = bytes; 358 } 359 if (fds == NULL) 360 goto fatal_err; 361 memcpy(fds, __svc_fdset, bytes); 362 363 FD_SET(sock, fds); 364 switch (select(svc_maxfd+1, fds, NULL, NULL, &delta)) { 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; 374 continue; 375 case 0: 376 goto fatal_err; 377 default: 378 if (!FD_ISSET(sock, fds)) { 379 svc_getreqset2(fds, svc_maxfd+1); 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; 386 continue; 387 } 388 } 389 } while (!FD_ISSET(sock, fds)); 390 if ((len = read(sock, buf, len)) > 0) { 391 if (fds) 392 free(fds); 393 return (len); 394 } 395 fatal_err: 396 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 397 if (fds) 398 free(fds); 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(xprt, buf, len) 408 register SVCXPRT *xprt; 409 caddr_t buf; 410 int len; 411 { 412 register int i, cnt; 413 414 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 415 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 416 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 417 XPRT_DIED; 418 return (-1); 419 } 420 } 421 return (len); 422 } 423 424 static enum xprt_stat 425 svctcp_stat(xprt) 426 SVCXPRT *xprt; 427 { 428 register struct tcp_conn *cd = 429 (struct tcp_conn *)(xprt->xp_p1); 430 431 if (cd->strm_stat == XPRT_DIED) 432 return (XPRT_DIED); 433 if (! xdrrec_eof(&(cd->xdrs))) 434 return (XPRT_MOREREQS); 435 return (XPRT_IDLE); 436 } 437 438 static bool_t 439 svctcp_recv(xprt, msg) 440 SVCXPRT *xprt; 441 register struct rpc_msg *msg; 442 { 443 register struct tcp_conn *cd = 444 (struct tcp_conn *)(xprt->xp_p1); 445 register XDR *xdrs = &(cd->xdrs); 446 447 xdrs->x_op = XDR_DECODE; 448 (void)xdrrec_skiprecord(xdrs); 449 if (xdr_callmsg(xdrs, msg)) { 450 cd->x_id = msg->rm_xid; 451 return (TRUE); 452 } 453 cd->strm_stat = XPRT_DIED; /* XXX */ 454 return (FALSE); 455 } 456 457 static bool_t 458 svctcp_getargs(xprt, xdr_args, args_ptr) 459 SVCXPRT *xprt; 460 xdrproc_t xdr_args; 461 caddr_t args_ptr; 462 { 463 464 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr)); 465 } 466 467 static bool_t 468 svctcp_freeargs(xprt, xdr_args, args_ptr) 469 SVCXPRT *xprt; 470 xdrproc_t xdr_args; 471 caddr_t args_ptr; 472 { 473 register XDR *xdrs = 474 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 475 476 xdrs->x_op = XDR_FREE; 477 return ((*xdr_args)(xdrs, args_ptr)); 478 } 479 480 static bool_t 481 svctcp_reply(xprt, msg) 482 SVCXPRT *xprt; 483 register struct rpc_msg *msg; 484 { 485 register struct tcp_conn *cd = 486 (struct tcp_conn *)(xprt->xp_p1); 487 register XDR *xdrs = &(cd->xdrs); 488 register bool_t stat; 489 490 xdrs->x_op = XDR_ENCODE; 491 msg->rm_xid = cd->x_id; 492 stat = xdr_replymsg(xdrs, msg); 493 (void)xdrrec_endofrecord(xdrs, TRUE); 494 return (stat); 495 } 496