1 2 /* 3 * Copyright (c) 2009, Sun Microsystems, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * - Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * - Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * - Neither the name of Sun Microsystems, Inc. nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 //#include <sys/cdefs.h> 31 32 /* 33 * svc_vc.c, Server side for Connection Oriented based RPC. 34 * 35 * Actually implements two flavors of transporter - 36 * a tcp rendezvouser (a listner and connection establisher) 37 * and a record/tcp stream. 38 */ 39 #include <wintirpc.h> 40 //#include <pthread.h> 41 #include <reentrant.h> 42 //#include <sys/socket.h> 43 #include <sys/types.h> 44 //#include <sys/param.h> 45 //#include <sys/poll.h> 46 //#include <sys/un.h> 47 //#include <sys/time.h> 48 //#include <sys/uio.h> 49 //#include <netinet/in.h> 50 //#include <netinet/tcp.h> 51 52 #include <assert.h> 53 //#include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 //#include <unistd.h> 60 61 #include <rpc/rpc.h> 62 63 #include "rpc_com.h" 64 65 #include <getpeereid.h> 66 67 68 extern rwlock_t svc_fd_lock; 69 70 static SVCXPRT *makefd_xprt(SOCKET, u_int, u_int); 71 static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 72 static enum xprt_stat rendezvous_stat(SVCXPRT *); 73 static void svc_vc_destroy(SVCXPRT *); 74 static void __svc_vc_dodestroy (SVCXPRT *); 75 static int read_vc(void *, void *, int); 76 static int write_vc(void *, void *, int); 77 static enum xprt_stat svc_vc_stat(SVCXPRT *); 78 static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 79 static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 80 static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 81 static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 82 static void svc_vc_rendezvous_ops(SVCXPRT *); 83 static void svc_vc_ops(SVCXPRT *); 84 static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 85 static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 86 void *in); 87 88 struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 89 u_int sendsize; 90 u_int recvsize; 91 int maxrec; 92 }; 93 94 struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 95 enum xprt_stat strm_stat; 96 u_int32_t x_id; 97 XDR xdrs; 98 char verf_body[MAX_AUTH_BYTES]; 99 u_int sendsize; 100 u_int recvsize; 101 int maxrec; 102 bool_t nonblock; 103 struct timeval last_recv_time; 104 }; 105 106 /* 107 * This is used to set xprt->xp_raddr in a way legacy 108 * apps can deal with 109 */ 110 void 111 __xprt_set_raddr(SVCXPRT *xprt, const struct sockaddr_storage *ss) 112 { 113 switch (ss->ss_family) { 114 case AF_INET6: 115 memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in6)); 116 xprt->xp_addrlen = sizeof (struct sockaddr_in6); 117 break; 118 case AF_INET: 119 memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in)); 120 xprt->xp_addrlen = sizeof (struct sockaddr_in); 121 break; 122 default: 123 xprt->xp_raddr.sin6_family = AF_UNSPEC; 124 xprt->xp_addrlen = sizeof (struct sockaddr); 125 break; 126 } 127 } 128 129 /* 130 * Usage: 131 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 132 * 133 * Creates, registers, and returns a (rpc) tcp based transporter. 134 * Once *xprt is initialized, it is registered as a transporter 135 * see (svc.h, xprt_register). This routine returns 136 * a NULL if a problem occurred. 137 * 138 * The filedescriptor passed in is expected to refer to a bound, but 139 * not yet connected socket. 140 * 141 * Since streams do buffered io similar to stdio, the caller can specify 142 * how big the send and receive buffers are via the second and third parms; 143 * 0 => use the system default. 144 */ 145 SVCXPRT * 146 svc_vc_create(fd, sendsize, recvsize) 147 int fd; 148 u_int sendsize; 149 u_int recvsize; 150 { 151 SVCXPRT *xprt; 152 struct cf_rendezvous *r = NULL; 153 struct __rpc_sockinfo si; 154 struct sockaddr_storage sslocal; 155 socklen_t slen; 156 157 r = mem_alloc(sizeof(*r)); 158 if (r == NULL) { 159 // XXX warnx("svc_vc_create: out of memory"); 160 goto cleanup_svc_vc_create; 161 } 162 if (!__rpc_fd2sockinfo(fd, &si)) 163 return NULL; 164 r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 165 r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 166 r->maxrec = __svc_maxrec; 167 xprt = mem_alloc(sizeof(SVCXPRT)); 168 if (xprt == NULL) { 169 // XXX warnx("svc_vc_create: out of memory"); 170 goto cleanup_svc_vc_create; 171 } 172 xprt->xp_tp = NULL; 173 xprt->xp_p1 = r; 174 xprt->xp_p2 = NULL; 175 xprt->xp_p3 = NULL; 176 xprt->xp_verf = _null_auth; 177 svc_vc_rendezvous_ops(xprt); 178 xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 179 xprt->xp_fd = fd; 180 181 slen = sizeof (struct sockaddr_storage); 182 if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) == SOCKET_ERROR) { 183 // XXX warnx("svc_vc_create: could not retrieve local addr"); 184 goto cleanup_svc_vc_create; 185 } 186 187 if (!__rpc_set_netbuf(&xprt->xp_ltaddr, &sslocal, sizeof(sslocal))) { 188 // XXX warnx("svc_vc_create: no mem for local addr"); 189 goto cleanup_svc_vc_create; 190 } 191 xprt_register(xprt); 192 return (xprt); 193 cleanup_svc_vc_create: 194 if (r != NULL) 195 mem_free(r, sizeof(*r)); 196 return (NULL); 197 } 198 199 /* 200 * Like svtcp_create(), except the routine takes any *open* UNIX file 201 * descriptor as its first input. 202 */ 203 SVCXPRT * 204 svc_fd_create(fd, sendsize, recvsize) 205 SOCKET fd; 206 u_int sendsize; 207 u_int recvsize; 208 { 209 struct sockaddr_storage ss; 210 socklen_t slen; 211 SVCXPRT *ret; 212 213 assert(fd != -1); 214 215 ret = makefd_xprt(fd, sendsize, recvsize); 216 if (ret == NULL) 217 return NULL; 218 219 slen = sizeof (struct sockaddr_storage); 220 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) { 221 // XXX warnx("svc_fd_create: could not retrieve local addr"); 222 goto freedata; 223 } 224 if (!__rpc_set_netbuf(&ret->xp_ltaddr, &ss, sizeof(ss))) { 225 // XXX warnx("svc_fd_create: no mem for local addr"); 226 goto freedata; 227 } 228 229 slen = sizeof (struct sockaddr_storage); 230 if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) { 231 // XXX warnx("svc_fd_create: could not retrieve remote addr"); 232 goto freedata; 233 } 234 if (!__rpc_set_netbuf(&ret->xp_rtaddr, &ss, sizeof(ss))) { 235 // XXX warnx("svc_fd_create: no mem for local addr"); 236 goto freedata; 237 } 238 239 /* Set xp_raddr for compatibility */ 240 __xprt_set_raddr(ret, &ss); 241 242 return ret; 243 244 freedata: 245 if (ret->xp_ltaddr.buf != NULL) 246 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 247 248 return NULL; 249 } 250 251 static SVCXPRT * 252 makefd_xprt(fd, sendsize, recvsize) 253 SOCKET fd; 254 u_int sendsize; 255 u_int recvsize; 256 { 257 SVCXPRT *xprt; 258 struct cf_conn *cd; 259 const char *netid; 260 struct __rpc_sockinfo si; 261 262 assert(fd != SOCKET_ERROR); 263 264 if (fd >= FD_SETSIZE) { 265 // XXX warnx("svc_vc: makefd_xprt: fd too high\n"); 266 xprt = NULL; 267 goto done; 268 } 269 270 xprt = mem_alloc(sizeof(SVCXPRT)); 271 if (xprt == NULL) { 272 // XXX warnx("svc_vc: makefd_xprt: out of memory"); 273 goto done; 274 } 275 memset(xprt, 0, sizeof *xprt); 276 cd = mem_alloc(sizeof(struct cf_conn)); 277 if (cd == NULL) { 278 // XXX warnx("svc_tcp: makefd_xprt: out of memory"); 279 mem_free(xprt, sizeof(SVCXPRT)); 280 xprt = NULL; 281 goto done; 282 } 283 cd->strm_stat = XPRT_IDLE; 284 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 285 xprt, read_vc, write_vc); 286 xprt->xp_p1 = cd; 287 xprt->xp_verf.oa_base = cd->verf_body; 288 svc_vc_ops(xprt); /* truely deals with calls */ 289 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 290 xprt->xp_fd = fd; 291 if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 292 xprt->xp_netid = strdup(netid); 293 294 xprt_register(xprt); 295 done: 296 return (xprt); 297 } 298 299 /*ARGSUSED*/ 300 static bool_t 301 rendezvous_request(xprt, msg) 302 SVCXPRT *xprt; 303 struct rpc_msg *msg; 304 { 305 SOCKET sock; 306 #ifndef _WIN32 307 int flags; 308 #endif 309 struct cf_rendezvous *r; 310 struct cf_conn *cd; 311 struct sockaddr_storage addr; 312 socklen_t len; 313 struct __rpc_sockinfo si; 314 SVCXPRT *newxprt; 315 fd_set cleanfds; 316 317 assert(xprt != NULL); 318 assert(msg != NULL); 319 320 r = (struct cf_rendezvous *)xprt->xp_p1; 321 again: 322 len = sizeof addr; 323 if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 324 &len)) == SOCKET_ERROR) { 325 if (errno == EINTR) 326 goto again; 327 #ifndef __REACTOS__ // CVE-2018-14621 328 /* 329 * Clean out the most idle file descriptor when we're 330 * running out. 331 */ 332 if (errno == EMFILE || errno == ENFILE) { 333 cleanfds = svc_fdset; 334 __svc_clean_idle(&cleanfds, 0, FALSE); 335 goto again; 336 } 337 #endif 338 return (FALSE); 339 } 340 /* 341 * make a new transporter (re-uses xprt) 342 */ 343 344 newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 345 #ifdef __REACTOS__ // CVE-2018-14622 346 if (!newxprt) 347 return (FALSE); 348 #endif 349 350 if (!__rpc_set_netbuf(&newxprt->xp_rtaddr, &addr, len)) 351 return (FALSE); 352 353 __xprt_set_raddr(newxprt, &addr); 354 355 if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 356 len = 1; 357 /* XXX fvdl - is this useful? */ 358 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&len, sizeof (len)); 359 } 360 361 cd = (struct cf_conn *)newxprt->xp_p1; 362 363 cd->recvsize = r->recvsize; 364 cd->sendsize = r->sendsize; 365 cd->maxrec = r->maxrec; 366 367 #ifndef _WIN32 368 if (cd->maxrec != 0) { 369 flags = fcntl(sock, F_GETFL, 0); 370 if (flags == -1) 371 return (FALSE); 372 if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 373 return (FALSE); 374 if (cd->recvsize > cd->maxrec) 375 cd->recvsize = cd->maxrec; 376 cd->nonblock = TRUE; 377 __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 378 } else 379 cd->nonblock = FALSE; 380 #endif /* _WIN32 */ 381 382 gettimeofday(&cd->last_recv_time, NULL); 383 384 return (FALSE); /* there is never an rpc msg to be processed */ 385 } 386 387 /*ARGSUSED*/ 388 static enum xprt_stat 389 rendezvous_stat(xprt) 390 SVCXPRT *xprt; 391 { 392 393 return (XPRT_IDLE); 394 } 395 396 static void 397 svc_vc_destroy(xprt) 398 SVCXPRT *xprt; 399 { 400 assert(xprt != NULL); 401 402 xprt_unregister(xprt); 403 __svc_vc_dodestroy(xprt); 404 } 405 406 static void 407 __svc_vc_dodestroy(xprt) 408 SVCXPRT *xprt; 409 { 410 struct cf_conn *cd; 411 struct cf_rendezvous *r; 412 413 cd = (struct cf_conn *)xprt->xp_p1; 414 415 if (xprt->xp_fd != RPC_ANYFD) 416 (void)closesocket(xprt->xp_fd); 417 if (xprt->xp_port != 0) { 418 /* a rendezvouser socket */ 419 r = (struct cf_rendezvous *)xprt->xp_p1; 420 mem_free(r, sizeof (struct cf_rendezvous)); 421 xprt->xp_port = 0; 422 } else { 423 /* an actual connection socket */ 424 XDR_DESTROY(&(cd->xdrs)); 425 mem_free(cd, sizeof(struct cf_conn)); 426 } 427 if (xprt->xp_rtaddr.buf) 428 mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 429 if (xprt->xp_ltaddr.buf) 430 mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 431 if (xprt->xp_tp) 432 free(xprt->xp_tp); 433 if (xprt->xp_netid) 434 free(xprt->xp_netid); 435 mem_free(xprt, sizeof(SVCXPRT)); 436 } 437 438 /*ARGSUSED*/ 439 static bool_t 440 svc_vc_control(xprt, rq, in) 441 SVCXPRT *xprt; 442 const u_int rq; 443 void *in; 444 { 445 return (FALSE); 446 } 447 448 static bool_t 449 svc_vc_rendezvous_control(xprt, rq, in) 450 SVCXPRT *xprt; 451 const u_int rq; 452 void *in; 453 { 454 struct cf_rendezvous *cfp; 455 456 cfp = (struct cf_rendezvous *)xprt->xp_p1; 457 if (cfp == NULL) 458 return (FALSE); 459 switch (rq) { 460 case SVCGET_CONNMAXREC: 461 *(int *)in = cfp->maxrec; 462 break; 463 case SVCSET_CONNMAXREC: 464 cfp->maxrec = *(int *)in; 465 break; 466 default: 467 return (FALSE); 468 } 469 return (TRUE); 470 } 471 472 /* 473 * reads data from the tcp or uip connection. 474 * any error is fatal and the connection is closed. 475 * (And a read of zero bytes is a half closed stream => error.) 476 * All read operations timeout after 35 seconds. A timeout is 477 * fatal for the connection. 478 */ 479 static int 480 read_vc(xprtp, buf, len) 481 void *xprtp; 482 void *buf; 483 int len; 484 { 485 SVCXPRT *xprt; 486 SOCKET sock; 487 int milliseconds = 35 * 1000; 488 struct pollfd pollfd; 489 struct cf_conn *cfp; 490 491 xprt = (SVCXPRT *)xprtp; 492 assert(xprt != NULL); 493 494 sock = xprt->xp_fd; 495 496 cfp = (struct cf_conn *)xprt->xp_p1; 497 498 if (cfp->nonblock) { 499 #ifdef _WIN32 500 len = recv(sock, buf, (size_t)len, 0); 501 #else 502 len = read(sock, buf, (size_t)len); 503 #endif 504 if (len == SOCKET_ERROR) { 505 if (WSAGetLastError() == EAGAIN) 506 len = 0; 507 else 508 goto fatal_err; 509 } 510 if (len != 0) 511 gettimeofday(&cfp->last_recv_time, NULL); 512 return len; 513 } 514 515 do { 516 #ifndef __REACTOS__ 517 pollfd.fd = sock; 518 pollfd.events = POLLIN; 519 pollfd.revents = 0; 520 switch (poll(&pollfd, 1, milliseconds)) { 521 #else 522 /* ReactOS: use select instead of poll */ 523 fd_set infd; 524 struct timeval timeout; 525 526 FD_ZERO(&infd); 527 FD_SET(sock, &infd); 528 529 timeout.tv_sec = 0; 530 timeout.tv_usec = milliseconds * 1000; 531 532 switch (select(0, &infd, NULL, NULL, &timeout)) { 533 #endif 534 case -1: 535 if (errno == EINTR) 536 continue; 537 /*FALLTHROUGH*/ 538 case 0: 539 goto fatal_err; 540 541 default: 542 break; 543 } 544 #ifndef __REACTOS__ 545 } while ((pollfd.revents & POLLIN) == 0); 546 #else 547 } while (TRUE); 548 #endif 549 550 #ifdef _WIN32 551 if ((len = recv(sock, buf, (size_t)len, 0)) > 0) { 552 #else 553 if ((len = read(sock, buf, (size_t)len)) > 0) { 554 #endif 555 gettimeofday(&cfp->last_recv_time, NULL); 556 return (len); 557 } 558 559 fatal_err: 560 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 561 return (-1); 562 } 563 564 /* 565 * writes data to the tcp connection. 566 * Any error is fatal and the connection is closed. 567 */ 568 static int 569 #ifdef __REACTOS__ 570 write_vc(xprtp, ptr, len) 571 #else 572 write_vc(xprtp, buf, len) 573 #endif 574 void *xprtp; 575 #ifdef __REACTOS__ 576 void *ptr; 577 #else 578 char *buf; 579 #endif 580 int len; 581 { 582 SVCXPRT *xprt; 583 int i, cnt; 584 struct cf_conn *cd; 585 struct timeval tv0, tv1; 586 #ifdef __REACTOS__ 587 char *buf = ptr; 588 #endif 589 590 xprt = (SVCXPRT *)xprtp; 591 assert(xprt != NULL); 592 593 cd = (struct cf_conn *)xprt->xp_p1; 594 595 if (cd->nonblock) 596 gettimeofday(&tv0, NULL); 597 598 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 599 #ifdef _WIN32 600 i = send(xprt->xp_fd, buf, (size_t)cnt, 0); 601 #else 602 i = write(xprt->xp_fd, buf, (size_t)cnt); 603 #endif 604 if (i == SOCKET_ERROR) { 605 if (WSAGetLastError() != EAGAIN || !cd->nonblock) { 606 cd->strm_stat = XPRT_DIED; 607 return (-1); 608 } 609 if (cd->nonblock && i != cnt) { 610 /* 611 * For non-blocking connections, do not 612 * take more than 2 seconds writing the 613 * data out. 614 * 615 * XXX 2 is an arbitrary amount. 616 */ 617 gettimeofday(&tv1, NULL); 618 if (tv1.tv_sec - tv0.tv_sec >= 2) { 619 cd->strm_stat = XPRT_DIED; 620 return (-1); 621 } 622 } 623 } 624 } 625 626 return (len); 627 } 628 629 static enum xprt_stat 630 svc_vc_stat(xprt) 631 SVCXPRT *xprt; 632 { 633 struct cf_conn *cd; 634 635 assert(xprt != NULL); 636 637 cd = (struct cf_conn *)(xprt->xp_p1); 638 639 if (cd->strm_stat == XPRT_DIED) 640 return (XPRT_DIED); 641 if (! xdrrec_eof(&(cd->xdrs))) 642 return (XPRT_MOREREQS); 643 return (XPRT_IDLE); 644 } 645 646 static bool_t 647 svc_vc_recv(xprt, msg) 648 SVCXPRT *xprt; 649 struct rpc_msg *msg; 650 { 651 struct cf_conn *cd; 652 XDR *xdrs; 653 654 assert(xprt != NULL); 655 assert(msg != NULL); 656 657 cd = (struct cf_conn *)(xprt->xp_p1); 658 xdrs = &(cd->xdrs); 659 660 if (cd->nonblock) { 661 if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 662 return FALSE; 663 } 664 665 xdrs->x_op = XDR_DECODE; 666 (void)xdrrec_skiprecord(xdrs); 667 if (xdr_callmsg(xdrs, msg)) { 668 cd->x_id = msg->rm_xid; 669 return (TRUE); 670 } 671 cd->strm_stat = XPRT_DIED; 672 return (FALSE); 673 } 674 675 static bool_t 676 svc_vc_getargs(xprt, xdr_args, args_ptr) 677 SVCXPRT *xprt; 678 xdrproc_t xdr_args; 679 void *args_ptr; 680 { 681 682 assert(xprt != NULL); 683 /* args_ptr may be NULL */ 684 return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 685 args_ptr)); 686 } 687 688 static bool_t 689 svc_vc_freeargs(xprt, xdr_args, args_ptr) 690 SVCXPRT *xprt; 691 xdrproc_t xdr_args; 692 void *args_ptr; 693 { 694 XDR *xdrs; 695 696 assert(xprt != NULL); 697 /* args_ptr may be NULL */ 698 699 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 700 701 xdrs->x_op = XDR_FREE; 702 return ((*xdr_args)(xdrs, args_ptr)); 703 } 704 705 static bool_t 706 svc_vc_reply(xprt, msg) 707 SVCXPRT *xprt; 708 struct rpc_msg *msg; 709 { 710 struct cf_conn *cd; 711 XDR *xdrs; 712 bool_t rstat; 713 714 assert(xprt != NULL); 715 assert(msg != NULL); 716 717 cd = (struct cf_conn *)(xprt->xp_p1); 718 xdrs = &(cd->xdrs); 719 720 xdrs->x_op = XDR_ENCODE; 721 msg->rm_xid = cd->x_id; 722 rstat = xdr_replymsg(xdrs, msg); 723 (void)xdrrec_endofrecord(xdrs, TRUE); 724 return (rstat); 725 } 726 727 static void 728 svc_vc_ops(xprt) 729 SVCXPRT *xprt; 730 { 731 static struct xp_ops ops; 732 static struct xp_ops2 ops2; 733 extern mutex_t ops_lock; 734 735 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 736 737 mutex_lock(&ops_lock); 738 if (ops.xp_recv == NULL) { 739 ops.xp_recv = svc_vc_recv; 740 ops.xp_stat = svc_vc_stat; 741 ops.xp_getargs = svc_vc_getargs; 742 ops.xp_reply = svc_vc_reply; 743 ops.xp_freeargs = svc_vc_freeargs; 744 ops.xp_destroy = svc_vc_destroy; 745 ops2.xp_control = svc_vc_control; 746 } 747 xprt->xp_ops = &ops; 748 xprt->xp_ops2 = &ops2; 749 mutex_unlock(&ops_lock); 750 } 751 752 static void 753 svc_vc_rendezvous_ops(xprt) 754 SVCXPRT *xprt; 755 { 756 static struct xp_ops ops; 757 static struct xp_ops2 ops2; 758 extern mutex_t ops_lock; 759 760 mutex_lock(&ops_lock); 761 if (ops.xp_recv == NULL) { 762 ops.xp_recv = rendezvous_request; 763 ops.xp_stat = rendezvous_stat; 764 ops.xp_getargs = 765 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 766 ops.xp_reply = 767 (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 768 ops.xp_freeargs = 769 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 770 ops.xp_destroy = svc_vc_destroy; 771 ops2.xp_control = svc_vc_rendezvous_control; 772 } 773 xprt->xp_ops = &ops; 774 xprt->xp_ops2 = &ops2; 775 mutex_unlock(&ops_lock); 776 } 777 778 /* 779 * Get the effective UID of the sending process. Used by rpcbind, keyserv 780 * and rpc.yppasswdd on AF_LOCAL. 781 */ 782 int 783 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 784 SOCKET sock; 785 int ret; 786 gid_t egid; 787 uid_t euid; 788 struct sockaddr *sa; 789 790 sock = transp->xp_fd; 791 sa = (struct sockaddr *)transp->xp_rtaddr.buf; 792 if (sa->sa_family == AF_UNIX) { 793 ret = getpeereid(sock, &euid, &egid); 794 if (ret == 0) 795 *uid = euid; 796 return (ret); 797 } else 798 return (-1); 799 } 800 801 #ifdef _WIN32 802 void timersub( const struct timeval *tvp, const struct timeval *uvp, struct timeval *vvp ) 803 { 804 vvp->tv_sec = tvp->tv_sec - uvp->tv_sec; 805 vvp->tv_usec = tvp->tv_usec - uvp->tv_usec; 806 if( vvp->tv_usec < 0 ) 807 { 808 --vvp->tv_sec; 809 vvp->tv_usec += 1000000; 810 } 811 } 812 #endif 813 814 /* 815 * Destroy xprts that have not have had any activity in 'timeout' seconds. 816 * If 'cleanblock' is true, blocking connections (the default) are also 817 * cleaned. If timeout is 0, the least active connection is picked. 818 */ 819 bool_t 820 __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 821 { 822 int i, ncleaned; 823 SVCXPRT *xprt, *least_active; 824 struct timeval tv, tdiff, tmax; 825 struct cf_conn *cd; 826 827 gettimeofday(&tv, NULL); 828 tmax.tv_sec = tmax.tv_usec = 0; 829 least_active = NULL; 830 rwlock_wrlock(&svc_fd_lock); 831 for (i = ncleaned = 0; i <= svc_maxfd; i++) { 832 if (FD_ISSET(i, fds)) { 833 xprt = __svc_xports[i]; 834 if (xprt == NULL || xprt->xp_ops == NULL || 835 xprt->xp_ops->xp_recv != svc_vc_recv) 836 continue; 837 cd = (struct cf_conn *)xprt->xp_p1; 838 if (!cleanblock && !cd->nonblock) 839 continue; 840 if (timeout == 0) { 841 timersub(&tv, &cd->last_recv_time, &tdiff); 842 if (timercmp(&tdiff, &tmax, >)) { 843 tmax = tdiff; 844 least_active = xprt; 845 } 846 continue; 847 } 848 if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 849 __xprt_unregister_unlocked(xprt); 850 __svc_vc_dodestroy(xprt); 851 ncleaned++; 852 } 853 } 854 } 855 if (timeout == 0 && least_active != NULL) { 856 __xprt_unregister_unlocked(least_active); 857 __svc_vc_dodestroy(least_active); 858 ncleaned++; 859 } 860 rwlock_unlock(&svc_fd_lock); 861 return ncleaned > 0 ? TRUE : FALSE; 862 } 863