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.
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.
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.
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.
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.
25
* Sun Microsystems, Inc.
27
* Mountain View, California 94043
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 */
35
* svc_tcp.c, Server side for TCP/IP based RPC.
37
* Copyright (C) 1984, Sun Microsystems, Inc.
39
* Actually implements two flavors of transporter -
40
* a tcp rendezvouser (a listner and connection establisher)
41
* and a record/tcp stream.
49
#include <sys/param.h>
50
#include <sys/socket.h>
53
#include <netinet/in_systm.h>
54
#include <netinet/in.h>
55
#include <netinet/ip.h>
57
#include <netinet/ip_var.h>
61
* Ops vector for TCP/IP based rpc service handle
63
static bool_t svctcp_recv();
64
static enum xprt_stat svctcp_stat();
65
static bool_t svctcp_getargs();
66
static bool_t svctcp_reply();
67
static bool_t svctcp_freeargs();
68
static void svctcp_destroy();
70
static struct xp_ops svctcp_op = {
80
* Ops vector for TCP/IP rendezvous handler
82
static bool_t rendezvous_request();
83
static enum xprt_stat rendezvous_stat();
85
static struct xp_ops svctcp_rendezvous_op = {
94
static int readtcp(), writetcp();
95
static SVCXPRT *makefd_xprt();
97
struct tcp_rendezvous { /* kept in xprt->xp_p1 */
102
struct tcp_conn { /* kept in xprt->xp_p1 */
103
enum xprt_stat strm_stat;
106
char verf_body[MAX_AUTH_BYTES];
111
* xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
113
* Creates, registers, and returns a (rpc) tcp based transporter.
114
* Once *xprt is initialized, it is registered as a transporter
115
* see (svc.h, xprt_register). This routine returns
116
* a NULL if a problem occurred.
118
* If sock<0 then a socket is created, else sock is used.
119
* If the socket, sock is not bound to a port then svctcp_create
120
* binds it to an arbitrary port. The routine then starts a tcp
121
* listener on the socket's associated port. In any (successful) case,
122
* xprt->xp_sock is the registered socket number and xprt->xp_port is the
123
* associated port number.
125
* Since tcp streams do buffered io similar to stdio, the caller can specify
126
* how big the send and receive buffers are via the second and third parms;
127
* 0 => use the system default.
130
svctcp_create(sock, sendsize, recvsize)
135
bool_t madesock = FALSE;
136
register SVCXPRT *xprt;
137
register struct tcp_rendezvous *r;
138
struct sockaddr_in addr;
139
int len = sizeof(struct sockaddr_in);
141
if (sock == RPC_ANYSOCK) {
142
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
143
perror("svctcp_.c - udp socket creation problem");
144
return ((SVCXPRT *)NULL);
148
memset(&addr, 0, sizeof (addr));
150
addr.sin_len = sizeof(struct sockaddr_in);
152
addr.sin_family = AF_INET;
153
if (bindresvport(sock, &addr)) {
155
(void)bind(sock, (struct sockaddr *)&addr, len);
157
if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) ||
158
(listen(sock, 2) != 0)) {
159
perror("svctcp_.c - cannot getsockname or listen");
162
return ((SVCXPRT *)NULL);
164
r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
166
(void)fprintf(stderr, "svctcp_create: out of memory\n");
171
r->sendsize = sendsize;
172
r->recvsize = recvsize;
173
xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
175
(void)fprintf(stderr, "svctcp_create: out of memory\n");
182
xprt->xp_p1 = (caddr_t)r;
183
xprt->xp_auth = NULL;
184
xprt->xp_verf = _null_auth;
185
xprt->xp_ops = &svctcp_rendezvous_op;
186
xprt->xp_port = ntohs(addr.sin_port);
187
xprt->xp_sock = sock;
193
* Like svtcp_create(), except the routine takes any *open* UNIX file
194
* descriptor as its first input.
197
svcfd_create(fd, sendsize, recvsize)
203
return (makefd_xprt(fd, sendsize, recvsize));
207
makefd_xprt(fd, sendsize, recvsize)
212
register SVCXPRT *xprt;
213
register struct tcp_conn *cd;
215
xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
216
if (xprt == (SVCXPRT *)NULL) {
217
(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
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;
227
cd->strm_stat = XPRT_IDLE;
228
xdrrec_create(&(cd->xdrs), sendsize, recvsize,
229
(caddr_t)xprt, readtcp, writetcp);
231
xprt->xp_p1 = (caddr_t)cd;
232
xprt->xp_auth = NULL;
233
xprt->xp_verf.oa_base = cd->verf_body;
234
xprt->xp_addrlen = 0;
235
xprt->xp_ops = &svctcp_op; /* truely deals with calls */
236
xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
244
rendezvous_request(xprt)
245
register SVCXPRT *xprt;
248
struct tcp_rendezvous *r;
249
struct sockaddr_in addr;
252
r = (struct tcp_rendezvous *)xprt->xp_p1;
254
len = sizeof(struct sockaddr_in);
255
if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
265
#define ipopt_list ip_opts
268
struct ipoption opts;
270
int optsize = sizeof(opts), i;
272
if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts,
273
&optsize) && optsize != 0) {
274
for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts <
276
u_char c = (u_char)opts.ipopt_list[i];
277
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
283
i += (c == IPOPT_NOP) ? 1 :
284
(u_char)opts.ipopt_list[i+1];
291
* XXX careful for ftp bounce attacks. If discovered, close the
292
* socket and look for another connection.
294
if (addr.sin_port == htons(20)) {
300
* make a new transporter (re-uses xprt)
302
xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
303
xprt->xp_raddr = addr;
304
xprt->xp_addrlen = len;
305
return (FALSE); /* there is never an rpc msg to be processed */
308
static enum xprt_stat
317
register SVCXPRT *xprt;
319
register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
321
xprt_unregister(xprt);
322
if (xprt->xp_sock != -1)
323
(void)close(xprt->xp_sock);
325
if (xprt->xp_port != 0) {
326
/* a rendezvouser socket */
329
/* an actual connection socket */
330
XDR_DESTROY(&(cd->xdrs));
332
if (xprt->xp_auth != NULL) {
333
SVCAUTH_DESTROY(xprt->xp_auth);
334
xprt->xp_auth = NULL;
336
mem_free((caddr_t)cd, sizeof(struct tcp_conn));
337
mem_free((caddr_t)xprt, sizeof(SVCXPRT));
341
* All read operations timeout after 35 seconds.
342
* A timeout is fatal for the connection.
344
static struct timeval wait_per_try = { 35, 0 };
347
* reads data from the tcp conection.
348
* any error is fatal and the connection is closed.
349
* (And a read of zero bytes is a half closed stream => error.)
352
readtcp(xprt, buf, len)
353
register SVCXPRT *xprt;
357
register int sock = xprt->xp_sock;
358
struct timeval start, delta;
359
struct timeval tmp1, tmp2;
361
int prevbytes = 0, bytes;
362
extern int __svc_fdsetsize;
363
extern fd_set *__svc_fdset;
365
delta = wait_per_try;
366
gettimeofday(&start, NULL);
368
bytes = howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask);
369
if (bytes != prevbytes) {
372
fds = (fd_set *)malloc(bytes);
377
memcpy(fds, __svc_fdset, bytes);
380
switch (select(svc_maxfd+1, fds, NULL, NULL, &delta)) {
384
gettimeofday(&tmp1, NULL);
385
timersub(&tmp1, &start, &tmp2);
386
timersub(&wait_per_try, &tmp2, &tmp1);
387
if (tmp1.tv_sec < 0 || !timerisset(&tmp1))
394
if (!FD_ISSET(sock, fds)) {
395
svc_getreqset2(fds, svc_maxfd+1);
396
gettimeofday(&tmp1, NULL);
397
timersub(&tmp1, &start, &tmp2);
398
timersub(&wait_per_try, &tmp2, &tmp1);
399
if (tmp1.tv_sec < 0 || !timerisset(&tmp1))
405
} while (!FD_ISSET(sock, fds));
406
if ((len = read(sock, buf, len)) > 0) {
412
((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
419
* writes data to the tcp connection.
420
* Any error is fatal and the connection is closed.
423
writetcp(xprt, buf, len)
424
register SVCXPRT *xprt;
430
for (cnt = len; cnt > 0; cnt -= i, buf += i) {
431
if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
432
((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
440
static enum xprt_stat
444
register struct tcp_conn *cd =
445
(struct tcp_conn *)(xprt->xp_p1);
447
if (cd->strm_stat == XPRT_DIED)
449
if (! xdrrec_eof(&(cd->xdrs)))
450
return (XPRT_MOREREQS);
455
svctcp_recv(xprt, msg)
457
register struct rpc_msg *msg;
459
register struct tcp_conn *cd =
460
(struct tcp_conn *)(xprt->xp_p1);
461
register XDR *xdrs = &(cd->xdrs);
463
xdrs->x_op = XDR_DECODE;
464
(void)xdrrec_skiprecord(xdrs);
465
if (xdr_callmsg(xdrs, msg)) {
466
cd->x_id = msg->rm_xid;
469
cd->strm_stat = XPRT_DIED; /* XXX */
474
svctcp_getargs(xprt, xdr_args, args_ptr)
479
return (SVCAUTH_UNWRAP(xprt->xp_auth,
480
&(((struct tcp_conn *)(xprt->xp_p1))->xdrs),
481
xdr_args, args_ptr));
485
svctcp_freeargs(xprt, xdr_args, args_ptr)
491
&(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
493
xdrs->x_op = XDR_FREE;
494
return ((*xdr_args)(xdrs, args_ptr));
498
svctcp_reply(xprt, msg)
500
register struct rpc_msg *msg;
502
register struct tcp_conn *cd =
503
(struct tcp_conn *)(xprt->xp_p1);
504
register XDR *xdrs = &(cd->xdrs);
508
xdrs->x_op = XDR_ENCODE;
509
msg->rm_xid = cd->x_id;
511
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
512
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
513
xdr_proc = msg->acpted_rply.ar_results.proc;
514
xdr_where = msg->acpted_rply.ar_results.where;
515
msg->acpted_rply.ar_results.proc = xdr_void;
516
msg->acpted_rply.ar_results.where = NULL;
518
if (!xdr_replymsg(xdrs, msg) ||
519
!SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where))
522
else if (!xdr_replymsg(xdrs, msg)) {
525
(void)xdrrec_endofrecord(xdrs, TRUE);