Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/rpc/svc_tcp.c
39536 views
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
534