~ubuntu-branches/ubuntu/lucid/nfs-utils/lucid

« back to all changes in this revision

Viewing changes to support/rpc/svc_tcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar
  • Date: 2006-07-03 10:36:59 UTC
  • mto: (12.1.1 feisty)
  • mto: This revision was merged to the branch mainline in revision 6.
  • Revision ID: james.westby@ubuntu.com-20060703103659-71qzs6f21zzmjmhx
Tags: upstream-1.0.8
ImportĀ upstreamĀ versionĀ 1.0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
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/param.h>
50
 
#include <sys/socket.h>
51
 
#include <errno.h>
52
 
 
53
 
#include <netinet/in_systm.h>
54
 
#include <netinet/in.h>
55
 
#include <netinet/ip.h>
56
 
#ifndef __linux__
57
 
#include <netinet/ip_var.h>
58
 
#endif
59
 
 
60
 
/*
61
 
 * Ops vector for TCP/IP based rpc service handle
62
 
 */
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();
69
 
 
70
 
static struct xp_ops svctcp_op = {
71
 
        svctcp_recv,
72
 
        svctcp_stat,
73
 
        svctcp_getargs,
74
 
        svctcp_reply,
75
 
        svctcp_freeargs,
76
 
        svctcp_destroy
77
 
};
78
 
 
79
 
/*
80
 
 * Ops vector for TCP/IP rendezvous handler
81
 
 */
82
 
static bool_t           rendezvous_request();
83
 
static enum xprt_stat   rendezvous_stat();
84
 
 
85
 
static struct xp_ops svctcp_rendezvous_op = {
86
 
        rendezvous_request,
87
 
        rendezvous_stat,
88
 
        (bool_t (*)())abort,
89
 
        (bool_t (*)())abort,
90
 
        (bool_t (*)())abort,
91
 
        svctcp_destroy
92
 
};
93
 
 
94
 
static int readtcp(), writetcp();
95
 
static SVCXPRT *makefd_xprt();
96
 
 
97
 
struct tcp_rendezvous { /* kept in xprt->xp_p1 */
98
 
        u_int sendsize;
99
 
        u_int recvsize;
100
 
};
101
 
 
102
 
struct tcp_conn {  /* kept in xprt->xp_p1 */
103
 
        enum xprt_stat strm_stat;
104
 
        u_long x_id;
105
 
        XDR xdrs;
106
 
        char verf_body[MAX_AUTH_BYTES];
107
 
};
108
 
 
109
 
/*
110
 
 * Usage:
111
 
 *      xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
112
 
 *
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.
117
 
 *
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.
124
 
 *
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.
128
 
 */
129
 
SVCXPRT *
130
 
svctcp_create(sock, sendsize, recvsize)
131
 
        register int sock;
132
 
        u_int sendsize;
133
 
        u_int recvsize;
134
 
{
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);
140
 
 
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);
145
 
                }
146
 
                madesock = TRUE;
147
 
        }
148
 
        memset(&addr, 0, sizeof (addr));
149
 
#ifndef __linux__
150
 
        addr.sin_len = sizeof(struct sockaddr_in);
151
 
#endif
152
 
        addr.sin_family = AF_INET;
153
 
        if (bindresvport(sock, &addr)) {
154
 
                addr.sin_port = 0;
155
 
                (void)bind(sock, (struct sockaddr *)&addr, len);
156
 
        }
157
 
        if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
158
 
            (listen(sock, 2) != 0)) {
159
 
                perror("svctcp_.c - cannot getsockname or listen");
160
 
                if (madesock)
161
 
                        (void)close(sock);
162
 
                return ((SVCXPRT *)NULL);
163
 
        }
164
 
        r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
165
 
        if (r == NULL) {
166
 
                (void)fprintf(stderr, "svctcp_create: out of memory\n");
167
 
                if (madesock)
168
 
                        (void)close(sock);
169
 
                return (NULL);
170
 
        }
171
 
        r->sendsize = sendsize;
172
 
        r->recvsize = recvsize;
173
 
        xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
174
 
        if (xprt == NULL) {
175
 
                (void)fprintf(stderr, "svctcp_create: out of memory\n");
176
 
                if (madesock)
177
 
                        (void)close(sock);
178
 
                free(r);
179
 
                return (NULL);
180
 
        }
181
 
        xprt->xp_p2 = NULL;
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;
188
 
        xprt_register(xprt);
189
 
        return (xprt);
190
 
}
191
 
 
192
 
/*
193
 
 * Like svtcp_create(), except the routine takes any *open* UNIX file
194
 
 * descriptor as its first input.
195
 
 */
196
 
SVCXPRT *
197
 
svcfd_create(fd, sendsize, recvsize)
198
 
        int fd;
199
 
        u_int sendsize;
200
 
        u_int recvsize;
201
 
{
202
 
 
203
 
        return (makefd_xprt(fd, sendsize, recvsize));
204
 
}
205
 
 
206
 
static SVCXPRT *
207
 
makefd_xprt(fd, sendsize, recvsize)
208
 
        int fd;
209
 
        u_int sendsize;
210
 
        u_int recvsize;
211
 
{
212
 
        register SVCXPRT *xprt;
213
 
        register struct tcp_conn *cd;
214
 
 
215
 
        xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
216
 
        if (xprt == (SVCXPRT *)NULL) {
217
 
                (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
218
 
                goto done;
219
 
        }
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;
225
 
                goto done;
226
 
        }
227
 
        cd->strm_stat = XPRT_IDLE;
228
 
        xdrrec_create(&(cd->xdrs), sendsize, recvsize,
229
 
            (caddr_t)xprt, readtcp, writetcp);
230
 
        xprt->xp_p2 = NULL;
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 */
237
 
        xprt->xp_sock = fd;
238
 
        xprt_register(xprt);
239
 
    done:
240
 
        return (xprt);
241
 
}
242
 
 
243
 
static bool_t
244
 
rendezvous_request(xprt)
245
 
        register SVCXPRT *xprt;
246
 
{
247
 
        int sock;
248
 
        struct tcp_rendezvous *r;
249
 
        struct sockaddr_in addr;
250
 
        int len;
251
 
 
252
 
        r = (struct tcp_rendezvous *)xprt->xp_p1;
253
 
    again:
254
 
        len = sizeof(struct sockaddr_in);
255
 
        if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
256
 
            &len)) < 0) {
257
 
                if (errno == EINTR)
258
 
                        goto again;
259
 
               return (FALSE);
260
 
        }
261
 
 
262
 
#ifdef IP_OPTIONS
263
 
        {
264
 
#ifdef __linux__
265
 
#define ipopt_list      ip_opts
266
 
                struct ip_opts opts;
267
 
#else
268
 
                struct ipoption opts;
269
 
#endif
270
 
                int optsize = sizeof(opts), i;
271
 
 
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 <
275
 
                            optsize; ) {
276
 
                                u_char c = (u_char)opts.ipopt_list[i];
277
 
                                if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
278
 
                                        close(sock);
279
 
                                        return (FALSE);
280
 
                                }
281
 
                                if (c == IPOPT_EOL)
282
 
                                        break;
283
 
                                i += (c == IPOPT_NOP) ? 1 :
284
 
                                    (u_char)opts.ipopt_list[i+1];
285
 
                        }
286
 
                }
287
 
        }
288
 
#endif
289
 
 
290
 
        /*
291
 
         * XXX careful for ftp bounce attacks. If discovered, close the
292
 
         * socket and look for another connection.
293
 
         */
294
 
        if (addr.sin_port == htons(20)) {
295
 
                close(sock);
296
 
                return (FALSE);
297
 
        }
298
 
 
299
 
        /*
300
 
         * make a new transporter (re-uses xprt)
301
 
         */
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 */
306
 
}
307
 
 
308
 
static enum xprt_stat
309
 
rendezvous_stat()
310
 
{
311
 
 
312
 
        return (XPRT_IDLE);
313
 
}
314
 
 
315
 
static void
316
 
svctcp_destroy(xprt)
317
 
        register SVCXPRT *xprt;
318
 
{
319
 
        register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
320
 
 
321
 
        xprt_unregister(xprt);
322
 
        if (xprt->xp_sock != -1)
323
 
                (void)close(xprt->xp_sock);
324
 
        xprt->xp_sock = -1;
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 conection.
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(xprt, buf, len)
353
 
        register SVCXPRT *xprt;
354
 
        caddr_t buf;
355
 
        register int len;
356
 
{
357
 
        register int sock = xprt->xp_sock;
358
 
        struct timeval start, delta;
359
 
        struct timeval tmp1, tmp2;
360
 
        fd_set *fds = NULL;
361
 
        int prevbytes = 0, bytes;
362
 
        extern int __svc_fdsetsize;
363
 
        extern fd_set *__svc_fdset;
364
 
 
365
 
        delta = wait_per_try;
366
 
        gettimeofday(&start, NULL);
367
 
        do {
368
 
                bytes = howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask);
369
 
                if (bytes != prevbytes) {
370
 
                        if (fds)
371
 
                                free(fds);
372
 
                        fds = (fd_set *)malloc(bytes);
373
 
                        prevbytes = bytes;
374
 
                }
375
 
                if (fds == NULL)
376
 
                        goto fatal_err;
377
 
                memcpy(fds, __svc_fdset, bytes);
378
 
 
379
 
                FD_SET(sock, fds);
380
 
                switch (select(svc_maxfd+1, fds, NULL, NULL, &delta)) {
381
 
                case -1:
382
 
                        if (errno != EINTR)
383
 
                                goto fatal_err;
384
 
                        gettimeofday(&tmp1, NULL);
385
 
                        timersub(&tmp1, &start, &tmp2);
386
 
                        timersub(&wait_per_try, &tmp2, &tmp1);
387
 
                        if (tmp1.tv_sec < 0 || !timerisset(&tmp1))
388
 
                                goto fatal_err;
389
 
                        delta = tmp1;
390
 
                        continue;
391
 
                case 0:
392
 
                        goto fatal_err;
393
 
                default:
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))
400
 
                                        goto fatal_err;
401
 
                                delta = tmp1;
402
 
                                continue;
403
 
                        }
404
 
                }
405
 
        } while (!FD_ISSET(sock, fds));
406
 
        if ((len = read(sock, buf, len)) > 0) {
407
 
                if (fds)
408
 
                        free(fds);
409
 
                return (len);
410
 
        }
411
 
fatal_err:
412
 
        ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
413
 
        if (fds)
414
 
                free(fds);
415
 
        return (-1);
416
 
}
417
 
 
418
 
/*
419
 
 * writes data to the tcp connection.
420
 
 * Any error is fatal and the connection is closed.
421
 
 */
422
 
static int
423
 
writetcp(xprt, buf, len)
424
 
        register SVCXPRT *xprt;
425
 
        caddr_t buf;
426
 
        int len;
427
 
{
428
 
        register int i, cnt;
429
 
 
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 =
433
 
                            XPRT_DIED;
434
 
                        return (-1);
435
 
                }
436
 
        }
437
 
        return (len);
438
 
}
439
 
 
440
 
static enum xprt_stat
441
 
svctcp_stat(xprt)
442
 
        SVCXPRT *xprt;
443
 
{
444
 
        register struct tcp_conn *cd =
445
 
            (struct tcp_conn *)(xprt->xp_p1);
446
 
 
447
 
        if (cd->strm_stat == XPRT_DIED)
448
 
                return (XPRT_DIED);
449
 
        if (! xdrrec_eof(&(cd->xdrs)))
450
 
                return (XPRT_MOREREQS);
451
 
        return (XPRT_IDLE);
452
 
}
453
 
 
454
 
static bool_t
455
 
svctcp_recv(xprt, msg)
456
 
        SVCXPRT *xprt;
457
 
        register struct rpc_msg *msg;
458
 
{
459
 
        register struct tcp_conn *cd =
460
 
            (struct tcp_conn *)(xprt->xp_p1);
461
 
        register XDR *xdrs = &(cd->xdrs);
462
 
 
463
 
        xdrs->x_op = XDR_DECODE;
464
 
        (void)xdrrec_skiprecord(xdrs);
465
 
        if (xdr_callmsg(xdrs, msg)) {
466
 
                cd->x_id = msg->rm_xid;
467
 
                return (TRUE);
468
 
        }
469
 
        cd->strm_stat = XPRT_DIED;      /* XXX */
470
 
        return (FALSE);
471
 
}
472
 
 
473
 
static bool_t
474
 
svctcp_getargs(xprt, xdr_args, args_ptr)
475
 
        SVCXPRT *xprt;
476
 
        xdrproc_t xdr_args;
477
 
        caddr_t args_ptr;
478
 
{
479
 
        return (SVCAUTH_UNWRAP(xprt->xp_auth,
480
 
                               &(((struct tcp_conn *)(xprt->xp_p1))->xdrs),
481
 
                               xdr_args, args_ptr));
482
 
}
483
 
 
484
 
static bool_t
485
 
svctcp_freeargs(xprt, xdr_args, args_ptr)
486
 
        SVCXPRT *xprt;
487
 
        xdrproc_t xdr_args;
488
 
        caddr_t args_ptr;
489
 
{
490
 
        register XDR *xdrs =
491
 
            &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
492
 
 
493
 
        xdrs->x_op = XDR_FREE;
494
 
        return ((*xdr_args)(xdrs, args_ptr));
495
 
}
496
 
 
497
 
static bool_t
498
 
svctcp_reply(xprt, msg)
499
 
        SVCXPRT *xprt;
500
 
        register struct rpc_msg *msg;
501
 
{
502
 
        register struct tcp_conn *cd =
503
 
            (struct tcp_conn *)(xprt->xp_p1);
504
 
        register XDR *xdrs = &(cd->xdrs);
505
 
        xdrproc_t xdr_proc;
506
 
        caddr_t xdr_where;
507
 
 
508
 
        xdrs->x_op = XDR_ENCODE;
509
 
        msg->rm_xid = cd->x_id;
510
 
 
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;
517
 
 
518
 
                if (!xdr_replymsg(xdrs, msg) ||
519
 
                    !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where))
520
 
                        return (FALSE);
521
 
        }
522
 
        else if (!xdr_replymsg(xdrs, msg)) {
523
 
                return (FALSE);
524
 
        }
525
 
        (void)xdrrec_endofrecord(xdrs, TRUE);
526
 
 
527
 
        return (TRUE);
528
 
}