1 /* @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC */ 2 /* 3 * Copyright (c) 2010, Oracle America, Inc. 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * * Neither the name of the "Oracle America, Inc." nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 28 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 #if !defined(lint) && defined(SCCSIDS) 35 static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 36 #endif 37 38 /* 39 * svc_tcp.c, Server side for TCP/IP based RPC. 40 * 41 * Actually implements two flavors of transporter - 42 * a tcp rendezvouser (a listener and connection establisher) 43 * and a record/tcp stream. 44 */ 45 46 #include "k5-platform.h" 47 #include <unistd.h> 48 #include <gssrpc/rpc.h> 49 #include <sys/socket.h> 50 #include <port-sockets.h> 51 #include <socket-utils.h> 52 /*extern bool_t abort(); 53 extern errno; 54 */ 55 56 #ifndef FD_SETSIZE 57 #ifdef NBBY 58 #define NOFILE (sizeof(int) * NBBY) 59 #else 60 #define NOFILE (sizeof(int) * 8) 61 #endif 62 #endif 63 64 /* 65 * Ops vector for TCP/IP based rpc service handle 66 */ 67 static bool_t svctcp_recv(SVCXPRT *, struct rpc_msg *); 68 static enum xprt_stat svctcp_stat(SVCXPRT *); 69 static bool_t svctcp_getargs(SVCXPRT *, xdrproc_t, void *); 70 static bool_t svctcp_reply(SVCXPRT *, struct rpc_msg *); 71 static bool_t svctcp_freeargs(SVCXPRT *, xdrproc_t, void *); 72 static void svctcp_destroy(SVCXPRT *); 73 74 static struct xp_ops svctcp_op = { 75 svctcp_recv, 76 svctcp_stat, 77 svctcp_getargs, 78 svctcp_reply, 79 svctcp_freeargs, 80 svctcp_destroy 81 }; 82 83 /* 84 * Ops vector for TCP/IP rendezvous handler 85 */ 86 static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 87 static bool_t abortx(void); 88 static bool_t abortx_getargs(SVCXPRT *, xdrproc_t, void *); 89 static bool_t abortx_reply(SVCXPRT *, struct rpc_msg *); 90 static bool_t abortx_freeargs(SVCXPRT *, xdrproc_t, void *); 91 static enum xprt_stat rendezvous_stat(SVCXPRT *); 92 93 static struct xp_ops svctcp_rendezvous_op = { 94 rendezvous_request, 95 rendezvous_stat, 96 abortx_getargs, 97 abortx_reply, 98 abortx_freeargs, 99 svctcp_destroy 100 }; 101 102 static int readtcp(char *, caddr_t, int), writetcp(char *, caddr_t, int); 103 static SVCXPRT *makefd_xprt(int, u_int, u_int); 104 105 struct tcp_rendezvous { /* kept in xprt->xp_p1 */ 106 u_int sendsize; 107 u_int recvsize; 108 }; 109 110 struct tcp_conn { /* kept in xprt->xp_p1 */ 111 enum xprt_stat strm_stat; 112 uint32_t x_id; 113 XDR xdrs; 114 char verf_body[MAX_AUTH_BYTES]; 115 }; 116 117 /* 118 * Usage: 119 * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); 120 * 121 * Creates, registers, and returns a (rpc) tcp based transporter. 122 * Once *xprt is initialized, it is registered as a transporter 123 * see (svc.h, xprt_register). This routine returns 124 * a NULL if a problem occurred. 125 * 126 * If sock<0 then a socket is created, else sock is used. 127 * If the socket, sock is not bound to a port then svctcp_create 128 * binds it to an arbitrary port. The routine then starts a tcp 129 * listener on the socket's associated port. In any (successful) case, 130 * xprt->xp_sock is the registered socket number and xprt->xp_port is the 131 * associated port number. 132 * 133 * Since tcp streams do buffered io similar to stdio, the caller can specify 134 * how big the send and receive buffers are via the second and third parms; 135 * 0 => use the system default. 136 */ 137 SVCXPRT * 138 svctcp_create( 139 SOCKET sock, 140 u_int sendsize, 141 u_int recvsize) 142 { 143 bool_t madesock = FALSE; 144 SVCXPRT *xprt; 145 struct tcp_rendezvous *r; 146 struct sockaddr_storage ss; 147 struct sockaddr *sa = (struct sockaddr *)&ss; 148 socklen_t len; 149 150 if (sock == RPC_ANYSOCK) { 151 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 152 perror("svctcp_.c - udp socket creation problem"); 153 return ((SVCXPRT *)NULL); 154 } 155 set_cloexec_fd(sock); 156 madesock = TRUE; 157 memset(&ss, 0, sizeof(ss)); 158 sa->sa_family = AF_INET; 159 } else { 160 len = sizeof(struct sockaddr_storage); 161 if (getsockname(sock, sa, &len) != 0) { 162 perror("svc_tcp.c - cannot getsockname"); 163 return ((SVCXPRT *)NULL); 164 } 165 } 166 167 if (bindresvport_sa(sock, sa)) { 168 sa_setport(sa, 0); 169 (void)bind(sock, sa, sa_socklen(sa)); 170 } 171 len = sizeof(struct sockaddr_storage); 172 if (getsockname(sock, sa, &len) != 0) { 173 perror("svc_tcp.c - cannot getsockname"); 174 if (madesock) 175 (void)closesocket(sock); 176 return ((SVCXPRT *)NULL); 177 } 178 if (listen(sock, 2) != 0) { 179 perror("svctcp_.c - cannot listen"); 180 if (madesock) 181 (void)closesocket(sock); 182 return ((SVCXPRT *)NULL); 183 } 184 r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); 185 if (r == NULL) { 186 (void) fprintf(stderr, "svctcp_create: out of memory\n"); 187 return (NULL); 188 } 189 r->sendsize = sendsize; 190 r->recvsize = recvsize; 191 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 192 if (xprt == NULL) { 193 (void) fprintf(stderr, "svctcp_create: out of memory\n"); 194 return (NULL); 195 } 196 xprt->xp_p2 = NULL; 197 xprt->xp_p1 = (caddr_t)r; 198 xprt->xp_auth = NULL; 199 xprt->xp_verf = gssrpc__null_auth; 200 xprt->xp_ops = &svctcp_rendezvous_op; 201 xprt->xp_port = sa_getport(sa); 202 xprt->xp_sock = sock; 203 xprt->xp_laddrlen = 0; 204 xprt_register(xprt); 205 return (xprt); 206 } 207 208 /* 209 * Like svtcp_create(), except the routine takes any *open* UNIX file 210 * descriptor as its first input. 211 */ 212 SVCXPRT * 213 svcfd_create( 214 int fd, 215 u_int sendsize, 216 u_int recvsize) 217 { 218 219 return (makefd_xprt(fd, sendsize, recvsize)); 220 } 221 222 static SVCXPRT * 223 makefd_xprt( 224 int fd, 225 u_int sendsize, 226 u_int recvsize) 227 { 228 SVCXPRT *xprt; 229 struct tcp_conn *cd; 230 231 #ifdef FD_SETSIZE 232 if (fd >= FD_SETSIZE) { 233 (void) fprintf(stderr, "svc_tcp: makefd_xprt: fd too high\n"); 234 xprt = NULL; 235 goto done; 236 } 237 #else 238 if (fd >= NOFILE) { 239 (void) fprintf(stderr, "svc_tcp: makefd_xprt: fd too high\n"); 240 xprt = NULL; 241 goto done; 242 } 243 #endif 244 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 245 if (xprt == (SVCXPRT *)NULL) { 246 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 247 goto done; 248 } 249 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 250 if (cd == (struct tcp_conn *)NULL) { 251 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 252 mem_free((char *) xprt, sizeof(SVCXPRT)); 253 xprt = (SVCXPRT *)NULL; 254 goto done; 255 } 256 cd->strm_stat = XPRT_IDLE; 257 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 258 (caddr_t)xprt, readtcp, writetcp); 259 xprt->xp_p2 = NULL; 260 xprt->xp_p1 = (caddr_t)cd; 261 xprt->xp_auth = NULL; 262 xprt->xp_verf.oa_base = cd->verf_body; 263 xprt->xp_addrlen = 0; 264 xprt->xp_laddrlen = 0; 265 xprt->xp_ops = &svctcp_op; /* truly deals with calls */ 266 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 267 xprt->xp_sock = fd; 268 xprt_register(xprt); 269 done: 270 return (xprt); 271 } 272 273 static bool_t 274 rendezvous_request( 275 SVCXPRT *xprt, 276 struct rpc_msg *msg) 277 { 278 SOCKET sock; 279 struct tcp_rendezvous *r; 280 struct sockaddr_in addr, laddr; 281 socklen_t len, llen; 282 283 r = (struct tcp_rendezvous *)xprt->xp_p1; 284 again: 285 len = llen = sizeof(struct sockaddr_in); 286 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, 287 &len)) < 0) { 288 if (errno == EINTR) 289 goto again; 290 return (FALSE); 291 } 292 set_cloexec_fd(sock); 293 if (getsockname(sock, (struct sockaddr *) &laddr, &llen) < 0) 294 return (FALSE); 295 296 /* 297 * make a new transporter (re-uses xprt) 298 */ 299 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 300 if (xprt == NULL) { 301 (void)closesocket(sock); 302 return (FALSE); 303 } 304 xprt->xp_raddr = addr; 305 xprt->xp_addrlen = len; 306 xprt->xp_laddr = laddr; 307 xprt->xp_laddrlen = llen; 308 return (FALSE); /* there is never an rpc msg to be processed */ 309 } 310 311 static enum xprt_stat 312 rendezvous_stat(SVCXPRT *xprt) 313 { 314 315 return (XPRT_IDLE); 316 } 317 318 static void 319 svctcp_destroy(SVCXPRT *xprt) 320 { 321 struct tcp_conn *cd = xprt->xp_p1; 322 323 xprt_unregister(xprt); 324 (void)closesocket(xprt->xp_sock); 325 if (xprt->xp_port != 0) { 326 /* a rendezvouser socket */ 327 xprt->xp_port = 0; 328 } else { 329 /* an actual connection socket */ 330 XDR_DESTROY(&(cd->xdrs)); 331 } 332 if (xprt->xp_auth != NULL) { 333 SVCAUTH_DESTROY(xprt->xp_auth); 334 xprt->xp_auth = NULL; 335 } 336 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 337 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 338 } 339 340 /* 341 * All read operations timeout after 35 seconds. 342 * A timeout is fatal for the connection. 343 */ 344 static struct timeval wait_per_try = { 35, 0 }; 345 346 /* 347 * reads data from the tcp connection. 348 * any error is fatal and the connection is closed. 349 * (And a read of zero bytes is a half closed stream => error.) 350 */ 351 static int 352 readtcp( 353 char *xprtptr, 354 caddr_t buf, 355 int len) 356 { 357 SVCXPRT *xprt = (void *)xprtptr; 358 int sock = xprt->xp_sock; 359 struct timeval tout; 360 #ifdef FD_SETSIZE 361 fd_set mask; 362 fd_set readfds; 363 364 FD_ZERO(&mask); 365 FD_SET(sock, &mask); 366 #else 367 int mask = 1 << sock; 368 int readfds; 369 #endif /* def FD_SETSIZE */ 370 #ifdef FD_SETSIZE 371 #define loopcond (!FD_ISSET(sock, &readfds)) 372 #else 373 #define loopcond (readfds != mask) 374 #endif 375 do { 376 readfds = mask; 377 tout = wait_per_try; 378 if (select(sock + 1, &readfds, (fd_set*)NULL, 379 (fd_set*)NULL, &tout) <= 0) { 380 if (errno == EINTR) { 381 continue; 382 } 383 goto fatal_err; 384 } 385 } while (loopcond); 386 if ((len = read(sock, buf, (size_t) len)) > 0) { 387 return (len); 388 } 389 fatal_err: 390 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 391 return (-1); 392 } 393 394 /* 395 * writes data to the tcp connection. 396 * Any error is fatal and the connection is closed. 397 */ 398 static int 399 writetcp( 400 char *xprtptr, 401 caddr_t buf, 402 int len) 403 { 404 SVCXPRT *xprt = (void *)xprtptr; 405 int i, cnt; 406 407 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 408 if ((i = write(xprt->xp_sock, buf, (size_t) cnt)) < 0) { 409 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 410 XPRT_DIED; 411 return (-1); 412 } 413 } 414 return (len); 415 } 416 417 static enum xprt_stat 418 svctcp_stat(SVCXPRT *xprt) 419 { 420 struct tcp_conn *cd = xprt->xp_p1; 421 422 if (cd->strm_stat == XPRT_DIED) 423 return (XPRT_DIED); 424 if (! xdrrec_eof(&(cd->xdrs))) 425 return (XPRT_MOREREQS); 426 return (XPRT_IDLE); 427 } 428 429 static bool_t 430 svctcp_recv( 431 SVCXPRT *xprt, 432 struct rpc_msg *msg) 433 { 434 struct tcp_conn *cd = xprt->xp_p1; 435 XDR *xdrs = &cd->xdrs; 436 437 xdrs->x_op = XDR_DECODE; 438 (void)xdrrec_skiprecord(xdrs); 439 if (xdr_callmsg(xdrs, msg)) { 440 cd->x_id = msg->rm_xid; 441 return (TRUE); 442 } 443 return (FALSE); 444 } 445 446 static bool_t 447 svctcp_getargs( 448 SVCXPRT *xprt, 449 xdrproc_t xdr_args, 450 void *args_ptr) 451 { 452 if (! SVCAUTH_UNWRAP(xprt->xp_auth, 453 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs), 454 xdr_args, args_ptr)) { 455 (void)svctcp_freeargs(xprt, xdr_args, args_ptr); 456 return FALSE; 457 } 458 return TRUE; 459 } 460 461 static bool_t 462 svctcp_freeargs( 463 SVCXPRT *xprt, 464 xdrproc_t xdr_args, 465 void * args_ptr) 466 { 467 XDR *xdrs = &((struct tcp_conn *)(xprt->xp_p1))->xdrs; 468 469 xdrs->x_op = XDR_FREE; 470 return ((*xdr_args)(xdrs, args_ptr)); 471 } 472 473 static bool_t svctcp_reply( 474 SVCXPRT *xprt, 475 struct rpc_msg *msg) 476 { 477 struct tcp_conn *cd = xprt->xp_p1; 478 XDR *xdrs = &cd->xdrs; 479 bool_t stat; 480 481 xdrproc_t xdr_results = NULL; 482 caddr_t xdr_location = 0; 483 bool_t has_args; 484 485 if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 486 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 487 has_args = TRUE; 488 xdr_results = msg->acpted_rply.ar_results.proc; 489 xdr_location = msg->acpted_rply.ar_results.where; 490 491 msg->acpted_rply.ar_results.proc = xdr_void; 492 msg->acpted_rply.ar_results.where = NULL; 493 } else 494 has_args = FALSE; 495 496 xdrs->x_op = XDR_ENCODE; 497 msg->rm_xid = cd->x_id; 498 stat = FALSE; 499 if (xdr_replymsg(xdrs, msg) && 500 (!has_args || 501 (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { 502 stat = TRUE; 503 } 504 (void)xdrrec_endofrecord(xdrs, TRUE); 505 return (stat); 506 } 507 508 static bool_t abortx(void) 509 { 510 abort(); 511 return 1; 512 } 513 514 static bool_t abortx_getargs( 515 SVCXPRT *xprt, 516 xdrproc_t proc, 517 void *info) 518 { 519 return abortx(); 520 } 521 522 static bool_t abortx_reply(SVCXPRT *xprt, struct rpc_msg *msg) 523 { 524 return abortx(); 525 } 526 527 static bool_t abortx_freeargs( 528 SVCXPRT *xprt, xdrproc_t proc, 529 void * info) 530 { 531 return abortx(); 532 } 533