3 * Copyright (c) 2009, Sun Microsystems, Inc.
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.
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.
30 //#include <sys/cdefs.h>
33 * svc_vc.c, Server side for Connection Oriented based RPC.
35 * Actually implements two flavors of transporter -
36 * a tcp rendezvouser (a listner and connection establisher)
37 * and a record/tcp stream.
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>
47 //#include <sys/time.h>
48 //#include <sys/uio.h>
49 //#include <netinet/in.h>
50 //#include <netinet/tcp.h>
65 #include <getpeereid.h>
68 extern rwlock_t svc_fd_lock
;
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
,
88 struct cf_rendezvous
{ /* kept in xprt->xp_p1 for rendezvouser */
94 struct cf_conn
{ /* kept in xprt->xp_p1 for actual connection */
95 enum xprt_stat strm_stat
;
98 char verf_body
[MAX_AUTH_BYTES
];
103 struct timeval last_recv_time
;
107 * This is used to set xprt->xp_raddr in a way legacy
111 __xprt_set_raddr(SVCXPRT
*xprt
, const struct sockaddr_storage
*ss
)
113 switch (ss
->ss_family
) {
115 memcpy(&xprt
->xp_raddr
, ss
, sizeof(struct sockaddr_in6
));
116 xprt
->xp_addrlen
= sizeof (struct sockaddr_in6
);
119 memcpy(&xprt
->xp_raddr
, ss
, sizeof(struct sockaddr_in
));
120 xprt
->xp_addrlen
= sizeof (struct sockaddr_in
);
123 xprt
->xp_raddr
.sin6_family
= AF_UNSPEC
;
124 xprt
->xp_addrlen
= sizeof (struct sockaddr
);
131 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
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.
138 * The filedescriptor passed in is expected to refer to a bound, but
139 * not yet connected socket.
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.
146 svc_vc_create(fd
, sendsize
, recvsize
)
152 struct cf_rendezvous
*r
= NULL
;
153 struct __rpc_sockinfo si
;
154 struct sockaddr_storage sslocal
;
157 r
= mem_alloc(sizeof(*r
));
159 // XXX warnx("svc_vc_create: out of memory");
160 goto cleanup_svc_vc_create
;
162 if (!__rpc_fd2sockinfo(fd
, &si
))
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
));
169 // XXX warnx("svc_vc_create: out of memory");
170 goto cleanup_svc_vc_create
;
176 xprt
->xp_verf
= _null_auth
;
177 svc_vc_rendezvous_ops(xprt
);
178 xprt
->xp_port
= (u_short
)-1; /* It is the rendezvouser */
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
;
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
;
193 cleanup_svc_vc_create
:
195 mem_free(r
, sizeof(*r
));
200 * Like svtcp_create(), except the routine takes any *open* UNIX file
201 * descriptor as its first input.
204 svc_fd_create(fd
, sendsize
, recvsize
)
209 struct sockaddr_storage ss
;
215 ret
= makefd_xprt(fd
, sendsize
, recvsize
);
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");
224 if (!__rpc_set_netbuf(&ret
->xp_ltaddr
, &ss
, sizeof(ss
))) {
225 // XXX warnx("svc_fd_create: no mem for local addr");
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");
234 if (!__rpc_set_netbuf(&ret
->xp_rtaddr
, &ss
, sizeof(ss
))) {
235 // XXX warnx("svc_fd_create: no mem for local addr");
239 /* Set xp_raddr for compatibility */
240 __xprt_set_raddr(ret
, &ss
);
245 if (ret
->xp_ltaddr
.buf
!= NULL
)
246 mem_free(ret
->xp_ltaddr
.buf
, rep
->xp_ltaddr
.maxlen
);
252 makefd_xprt(fd
, sendsize
, recvsize
)
260 struct __rpc_sockinfo si
;
262 assert(fd
!= SOCKET_ERROR
);
264 if (fd
>= FD_SETSIZE
) {
265 // XXX warnx("svc_vc: makefd_xprt: fd too high\n");
270 xprt
= mem_alloc(sizeof(SVCXPRT
));
272 // XXX warnx("svc_vc: makefd_xprt: out of memory");
275 memset(xprt
, 0, sizeof *xprt
);
276 cd
= mem_alloc(sizeof(struct cf_conn
));
278 // XXX warnx("svc_tcp: makefd_xprt: out of memory");
279 mem_free(xprt
, sizeof(SVCXPRT
));
283 cd
->strm_stat
= XPRT_IDLE
;
284 xdrrec_create(&(cd
->xdrs
), sendsize
, recvsize
,
285 xprt
, read_vc
, write_vc
);
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 */
291 if (__rpc_fd2sockinfo(fd
, &si
) && __rpc_sockinfo2netid(&si
, &netid
))
292 xprt
->xp_netid
= strdup(netid
);
301 rendezvous_request(xprt
, msg
)
309 struct cf_rendezvous
*r
;
311 struct sockaddr_storage addr
;
313 struct __rpc_sockinfo si
;
317 assert(xprt
!= NULL
);
320 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
323 if ((sock
= accept(xprt
->xp_fd
, (struct sockaddr
*)(void *)&addr
,
324 &len
)) == SOCKET_ERROR
) {
328 * Clean out the most idle file descriptor when we're
331 if (errno
== EMFILE
|| errno
== ENFILE
) {
332 cleanfds
= svc_fdset
;
333 __svc_clean_idle(&cleanfds
, 0, FALSE
);
339 * make a new transporter (re-uses xprt)
342 newxprt
= makefd_xprt(sock
, r
->sendsize
, r
->recvsize
);
343 #ifdef __REACTOS__ // CVE-2018-14622
348 if (!__rpc_set_netbuf(&newxprt
->xp_rtaddr
, &addr
, len
))
351 __xprt_set_raddr(newxprt
, &addr
);
353 if (__rpc_fd2sockinfo(sock
, &si
) && si
.si_proto
== IPPROTO_TCP
) {
355 /* XXX fvdl - is this useful? */
356 setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&len
, sizeof (len
));
359 cd
= (struct cf_conn
*)newxprt
->xp_p1
;
361 cd
->recvsize
= r
->recvsize
;
362 cd
->sendsize
= r
->sendsize
;
363 cd
->maxrec
= r
->maxrec
;
366 if (cd
->maxrec
!= 0) {
367 flags
= fcntl(sock
, F_GETFL
, 0);
370 if (fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
372 if (cd
->recvsize
> cd
->maxrec
)
373 cd
->recvsize
= cd
->maxrec
;
375 __xdrrec_setnonblock(&cd
->xdrs
, cd
->maxrec
);
377 cd
->nonblock
= FALSE
;
380 gettimeofday(&cd
->last_recv_time
, NULL
);
382 return (FALSE
); /* there is never an rpc msg to be processed */
386 static enum xprt_stat
387 rendezvous_stat(xprt
)
398 assert(xprt
!= NULL
);
400 xprt_unregister(xprt
);
401 __svc_vc_dodestroy(xprt
);
405 __svc_vc_dodestroy(xprt
)
409 struct cf_rendezvous
*r
;
411 cd
= (struct cf_conn
*)xprt
->xp_p1
;
413 if (xprt
->xp_fd
!= RPC_ANYFD
)
414 (void)closesocket(xprt
->xp_fd
);
415 if (xprt
->xp_port
!= 0) {
416 /* a rendezvouser socket */
417 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
418 mem_free(r
, sizeof (struct cf_rendezvous
));
421 /* an actual connection socket */
422 XDR_DESTROY(&(cd
->xdrs
));
423 mem_free(cd
, sizeof(struct cf_conn
));
425 if (xprt
->xp_rtaddr
.buf
)
426 mem_free(xprt
->xp_rtaddr
.buf
, xprt
->xp_rtaddr
.maxlen
);
427 if (xprt
->xp_ltaddr
.buf
)
428 mem_free(xprt
->xp_ltaddr
.buf
, xprt
->xp_ltaddr
.maxlen
);
432 free(xprt
->xp_netid
);
433 mem_free(xprt
, sizeof(SVCXPRT
));
438 svc_vc_control(xprt
, rq
, in
)
447 svc_vc_rendezvous_control(xprt
, rq
, in
)
452 struct cf_rendezvous
*cfp
;
454 cfp
= (struct cf_rendezvous
*)xprt
->xp_p1
;
458 case SVCGET_CONNMAXREC
:
459 *(int *)in
= cfp
->maxrec
;
461 case SVCSET_CONNMAXREC
:
462 cfp
->maxrec
= *(int *)in
;
471 * reads data from the tcp or uip connection.
472 * any error is fatal and the connection is closed.
473 * (And a read of zero bytes is a half closed stream => error.)
474 * All read operations timeout after 35 seconds. A timeout is
475 * fatal for the connection.
478 read_vc(xprtp
, buf
, len
)
485 int milliseconds
= 35 * 1000;
486 struct pollfd pollfd
;
489 xprt
= (SVCXPRT
*)xprtp
;
490 assert(xprt
!= NULL
);
494 cfp
= (struct cf_conn
*)xprt
->xp_p1
;
498 len
= recv(sock
, buf
, (size_t)len
, 0);
500 len
= read(sock
, buf
, (size_t)len
);
502 if (len
== SOCKET_ERROR
) {
503 if (WSAGetLastError() == EAGAIN
)
509 gettimeofday(&cfp
->last_recv_time
, NULL
);
516 pollfd
.events
= POLLIN
;
518 switch (poll(&pollfd
, 1, milliseconds
)) {
520 /* ReactOS: use select instead of poll */
522 struct timeval timeout
;
528 timeout
.tv_usec
= milliseconds
* 1000;
530 switch (select(0, &infd
, NULL
, NULL
, &timeout
)) {
543 } while ((pollfd
.revents
& POLLIN
) == 0);
549 if ((len
= recv(sock
, buf
, (size_t)len
, 0)) > 0) {
551 if ((len
= read(sock
, buf
, (size_t)len
)) > 0) {
553 gettimeofday(&cfp
->last_recv_time
, NULL
);
558 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
563 * writes data to the tcp connection.
564 * Any error is fatal and the connection is closed.
568 write_vc(xprtp
, ptr
, len
)
570 write_vc(xprtp
, buf
, len
)
583 struct timeval tv0
, tv1
;
588 xprt
= (SVCXPRT
*)xprtp
;
589 assert(xprt
!= NULL
);
591 cd
= (struct cf_conn
*)xprt
->xp_p1
;
594 gettimeofday(&tv0
, NULL
);
596 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
598 i
= send(xprt
->xp_fd
, buf
, (size_t)cnt
, 0);
600 i
= write(xprt
->xp_fd
, buf
, (size_t)cnt
);
602 if (i
== SOCKET_ERROR
) {
603 if (WSAGetLastError() != EAGAIN
|| !cd
->nonblock
) {
604 cd
->strm_stat
= XPRT_DIED
;
607 if (cd
->nonblock
&& i
!= cnt
) {
609 * For non-blocking connections, do not
610 * take more than 2 seconds writing the
613 * XXX 2 is an arbitrary amount.
615 gettimeofday(&tv1
, NULL
);
616 if (tv1
.tv_sec
- tv0
.tv_sec
>= 2) {
617 cd
->strm_stat
= XPRT_DIED
;
627 static enum xprt_stat
633 assert(xprt
!= NULL
);
635 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
637 if (cd
->strm_stat
== XPRT_DIED
)
639 if (! xdrrec_eof(&(cd
->xdrs
)))
640 return (XPRT_MOREREQS
);
645 svc_vc_recv(xprt
, msg
)
652 assert(xprt
!= NULL
);
655 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
659 if (!__xdrrec_getrec(xdrs
, &cd
->strm_stat
, TRUE
))
663 xdrs
->x_op
= XDR_DECODE
;
664 (void)xdrrec_skiprecord(xdrs
);
665 if (xdr_callmsg(xdrs
, msg
)) {
666 cd
->x_id
= msg
->rm_xid
;
669 cd
->strm_stat
= XPRT_DIED
;
674 svc_vc_getargs(xprt
, xdr_args
, args_ptr
)
680 assert(xprt
!= NULL
);
681 /* args_ptr may be NULL */
682 return ((*xdr_args
)(&(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
),
687 svc_vc_freeargs(xprt
, xdr_args
, args_ptr
)
694 assert(xprt
!= NULL
);
695 /* args_ptr may be NULL */
697 xdrs
= &(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
);
699 xdrs
->x_op
= XDR_FREE
;
700 return ((*xdr_args
)(xdrs
, args_ptr
));
704 svc_vc_reply(xprt
, msg
)
712 assert(xprt
!= NULL
);
715 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
718 xdrs
->x_op
= XDR_ENCODE
;
719 msg
->rm_xid
= cd
->x_id
;
720 rstat
= xdr_replymsg(xdrs
, msg
);
721 (void)xdrrec_endofrecord(xdrs
, TRUE
);
729 static struct xp_ops ops
;
730 static struct xp_ops2 ops2
;
731 extern mutex_t ops_lock
;
733 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
735 mutex_lock(&ops_lock
);
736 if (ops
.xp_recv
== NULL
) {
737 ops
.xp_recv
= svc_vc_recv
;
738 ops
.xp_stat
= svc_vc_stat
;
739 ops
.xp_getargs
= svc_vc_getargs
;
740 ops
.xp_reply
= svc_vc_reply
;
741 ops
.xp_freeargs
= svc_vc_freeargs
;
742 ops
.xp_destroy
= svc_vc_destroy
;
743 ops2
.xp_control
= svc_vc_control
;
746 xprt
->xp_ops2
= &ops2
;
747 mutex_unlock(&ops_lock
);
751 svc_vc_rendezvous_ops(xprt
)
754 static struct xp_ops ops
;
755 static struct xp_ops2 ops2
;
756 extern mutex_t ops_lock
;
758 mutex_lock(&ops_lock
);
759 if (ops
.xp_recv
== NULL
) {
760 ops
.xp_recv
= rendezvous_request
;
761 ops
.xp_stat
= rendezvous_stat
;
763 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
;
765 (bool_t (*)(SVCXPRT
*, struct rpc_msg
*))abort
;
767 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
,
768 ops
.xp_destroy
= svc_vc_destroy
;
769 ops2
.xp_control
= svc_vc_rendezvous_control
;
772 xprt
->xp_ops2
= &ops2
;
773 mutex_unlock(&ops_lock
);
777 * Get the effective UID of the sending process. Used by rpcbind, keyserv
778 * and rpc.yppasswdd on AF_LOCAL.
781 __rpc_get_local_uid(SVCXPRT
*transp
, uid_t
*uid
) {
788 sock
= transp
->xp_fd
;
789 sa
= (struct sockaddr
*)transp
->xp_rtaddr
.buf
;
790 if (sa
->sa_family
== AF_UNIX
) {
791 ret
= getpeereid(sock
, &euid
, &egid
);
800 void timersub( const struct timeval
*tvp
, const struct timeval
*uvp
, struct timeval
*vvp
)
802 vvp
->tv_sec
= tvp
->tv_sec
- uvp
->tv_sec
;
803 vvp
->tv_usec
= tvp
->tv_usec
- uvp
->tv_usec
;
804 if( vvp
->tv_usec
< 0 )
807 vvp
->tv_usec
+= 1000000;
813 * Destroy xprts that have not have had any activity in 'timeout' seconds.
814 * If 'cleanblock' is true, blocking connections (the default) are also
815 * cleaned. If timeout is 0, the least active connection is picked.
818 __svc_clean_idle(fd_set
*fds
, int timeout
, bool_t cleanblock
)
821 SVCXPRT
*xprt
, *least_active
;
822 struct timeval tv
, tdiff
, tmax
;
825 gettimeofday(&tv
, NULL
);
826 tmax
.tv_sec
= tmax
.tv_usec
= 0;
828 rwlock_wrlock(&svc_fd_lock
);
829 for (i
= ncleaned
= 0; i
<= svc_maxfd
; i
++) {
830 if (FD_ISSET(i
, fds
)) {
831 xprt
= __svc_xports
[i
];
832 if (xprt
== NULL
|| xprt
->xp_ops
== NULL
||
833 xprt
->xp_ops
->xp_recv
!= svc_vc_recv
)
835 cd
= (struct cf_conn
*)xprt
->xp_p1
;
836 if (!cleanblock
&& !cd
->nonblock
)
839 timersub(&tv
, &cd
->last_recv_time
, &tdiff
);
840 if (timercmp(&tdiff
, &tmax
, >)) {
846 if (tv
.tv_sec
- cd
->last_recv_time
.tv_sec
> timeout
) {
847 __xprt_unregister_unlocked(xprt
);
848 __svc_vc_dodestroy(xprt
);
853 if (timeout
== 0 && least_active
!= NULL
) {
854 __xprt_unregister_unlocked(least_active
);
855 __svc_vc_dodestroy(least_active
);
858 rwlock_unlock(&svc_fd_lock
);
859 return ncleaned
> 0 ? TRUE
: FALSE
;