1*7f2fe78bSCy Schubert /* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert * Copyright (c) 2010, Oracle America, Inc.
4*7f2fe78bSCy Schubert *
5*7f2fe78bSCy Schubert * All rights reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Redistribution and use in source and binary forms, with or without
8*7f2fe78bSCy Schubert * modification, are permitted provided that the following conditions are met:
9*7f2fe78bSCy Schubert *
10*7f2fe78bSCy Schubert * * Redistributions of source code must retain the above copyright
11*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer.
12*7f2fe78bSCy Schubert *
13*7f2fe78bSCy Schubert * * Redistributions in binary form must reproduce the above copyright
14*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer in
15*7f2fe78bSCy Schubert * the documentation and/or other materials provided with the
16*7f2fe78bSCy Schubert * distribution.
17*7f2fe78bSCy Schubert *
18*7f2fe78bSCy Schubert * * Neither the name of the "Oracle America, Inc." nor the names of
19*7f2fe78bSCy Schubert * its contributors may be used to endorse or promote products
20*7f2fe78bSCy Schubert * derived from this software without specific prior written permission.
21*7f2fe78bSCy Schubert *
22*7f2fe78bSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23*7f2fe78bSCy Schubert * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24*7f2fe78bSCy Schubert * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25*7f2fe78bSCy Schubert * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26*7f2fe78bSCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27*7f2fe78bSCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28*7f2fe78bSCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29*7f2fe78bSCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30*7f2fe78bSCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31*7f2fe78bSCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32*7f2fe78bSCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33*7f2fe78bSCy Schubert */
34*7f2fe78bSCy Schubert #if !defined(lint) && defined(SCCSIDS)
35*7f2fe78bSCy Schubert static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
36*7f2fe78bSCy Schubert #endif
37*7f2fe78bSCy Schubert
38*7f2fe78bSCy Schubert /*
39*7f2fe78bSCy Schubert * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
40*7f2fe78bSCy Schubert *
41*7f2fe78bSCy Schubert * TCP based RPC supports 'batched calls'.
42*7f2fe78bSCy Schubert * A sequence of calls may be batched-up in a send buffer. The rpc call
43*7f2fe78bSCy Schubert * return immediately to the client even though the call was not necessarily
44*7f2fe78bSCy Schubert * sent. The batching occurs if the results' xdr routine is NULL (0) AND
45*7f2fe78bSCy Schubert * the rpc timeout value is zero (see clnt.h, rpc).
46*7f2fe78bSCy Schubert *
47*7f2fe78bSCy Schubert * Clients should NOT casually batch calls that in fact return results; that is,
48*7f2fe78bSCy Schubert * the server side should be aware that a call is batched and not produce any
49*7f2fe78bSCy Schubert * return message. Batched calls that produce many result messages can
50*7f2fe78bSCy Schubert * deadlock (netlock) the client and the server....
51*7f2fe78bSCy Schubert *
52*7f2fe78bSCy Schubert * Now go hang yourself.
53*7f2fe78bSCy Schubert */
54*7f2fe78bSCy Schubert
55*7f2fe78bSCy Schubert #include <stdio.h>
56*7f2fe78bSCy Schubert #include <unistd.h>
57*7f2fe78bSCy Schubert #include <gssrpc/rpc.h>
58*7f2fe78bSCy Schubert #include <sys/socket.h>
59*7f2fe78bSCy Schubert #include <netdb.h>
60*7f2fe78bSCy Schubert #include <errno.h>
61*7f2fe78bSCy Schubert #include <string.h>
62*7f2fe78bSCy Schubert #include <gssrpc/pmap_clnt.h>
63*7f2fe78bSCy Schubert /* FD_ZERO may need memset declaration (e.g., Solaris 9) */
64*7f2fe78bSCy Schubert #include <string.h>
65*7f2fe78bSCy Schubert #include <port-sockets.h>
66*7f2fe78bSCy Schubert
67*7f2fe78bSCy Schubert #define MCALL_MSG_SIZE 24
68*7f2fe78bSCy Schubert
69*7f2fe78bSCy Schubert #ifndef GETSOCKNAME_ARG3_TYPE
70*7f2fe78bSCy Schubert #define GETSOCKNAME_ARG3_TYPE int
71*7f2fe78bSCy Schubert #endif
72*7f2fe78bSCy Schubert
73*7f2fe78bSCy Schubert static enum clnt_stat clnttcp_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
74*7f2fe78bSCy Schubert xdrproc_t, void *, struct timeval);
75*7f2fe78bSCy Schubert static void clnttcp_abort(CLIENT *);
76*7f2fe78bSCy Schubert static void clnttcp_geterr(CLIENT *, struct rpc_err *);
77*7f2fe78bSCy Schubert static bool_t clnttcp_freeres(CLIENT *, xdrproc_t, void *);
78*7f2fe78bSCy Schubert static bool_t clnttcp_control(CLIENT *, int, void *);
79*7f2fe78bSCy Schubert static void clnttcp_destroy(CLIENT *);
80*7f2fe78bSCy Schubert
81*7f2fe78bSCy Schubert static struct clnt_ops tcp_ops = {
82*7f2fe78bSCy Schubert clnttcp_call,
83*7f2fe78bSCy Schubert clnttcp_abort,
84*7f2fe78bSCy Schubert clnttcp_geterr,
85*7f2fe78bSCy Schubert clnttcp_freeres,
86*7f2fe78bSCy Schubert clnttcp_destroy,
87*7f2fe78bSCy Schubert clnttcp_control
88*7f2fe78bSCy Schubert };
89*7f2fe78bSCy Schubert
90*7f2fe78bSCy Schubert struct ct_data {
91*7f2fe78bSCy Schubert int ct_sock;
92*7f2fe78bSCy Schubert bool_t ct_closeit;
93*7f2fe78bSCy Schubert struct timeval ct_wait;
94*7f2fe78bSCy Schubert bool_t ct_waitset; /* wait set by clnt_control? */
95*7f2fe78bSCy Schubert struct sockaddr_in ct_addr;
96*7f2fe78bSCy Schubert struct rpc_err ct_error;
97*7f2fe78bSCy Schubert union {
98*7f2fe78bSCy Schubert char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
99*7f2fe78bSCy Schubert uint32_t ct_mcalli;
100*7f2fe78bSCy Schubert } ct_u;
101*7f2fe78bSCy Schubert u_int ct_mpos; /* pos after marshal */
102*7f2fe78bSCy Schubert XDR ct_xdrs;
103*7f2fe78bSCy Schubert };
104*7f2fe78bSCy Schubert
105*7f2fe78bSCy Schubert static int readtcp(char *, caddr_t, int);
106*7f2fe78bSCy Schubert static int writetcp(char *, caddr_t, int);
107*7f2fe78bSCy Schubert
108*7f2fe78bSCy Schubert
109*7f2fe78bSCy Schubert /*
110*7f2fe78bSCy Schubert * Create a client handle for a tcp/ip connection.
111*7f2fe78bSCy Schubert * If *sockp<0, *sockp is set to a newly created TCP socket and it is
112*7f2fe78bSCy Schubert * connected to raddr. If *sockp non-negative then
113*7f2fe78bSCy Schubert * raddr is ignored. The rpc/tcp package does buffering
114*7f2fe78bSCy Schubert * similar to stdio, so the client must pick send and receive buffer sizes,];
115*7f2fe78bSCy Schubert * 0 => use the default.
116*7f2fe78bSCy Schubert * If raddr->sin_port is 0, then a binder on the remote machine is
117*7f2fe78bSCy Schubert * consulted for the right port number.
118*7f2fe78bSCy Schubert * NB: *sockp is copied into a private area.
119*7f2fe78bSCy Schubert * NB: It is the clients responsibility to close *sockp.
120*7f2fe78bSCy Schubert * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
121*7f2fe78bSCy Schubert * something more useful.
122*7f2fe78bSCy Schubert */
123*7f2fe78bSCy Schubert CLIENT *
clnttcp_create(struct sockaddr_in * raddr,rpcprog_t prog,rpcvers_t vers,SOCKET * sockp,u_int sendsz,u_int recvsz)124*7f2fe78bSCy Schubert clnttcp_create(
125*7f2fe78bSCy Schubert struct sockaddr_in *raddr,
126*7f2fe78bSCy Schubert rpcprog_t prog,
127*7f2fe78bSCy Schubert rpcvers_t vers,
128*7f2fe78bSCy Schubert SOCKET *sockp,
129*7f2fe78bSCy Schubert u_int sendsz,
130*7f2fe78bSCy Schubert u_int recvsz)
131*7f2fe78bSCy Schubert {
132*7f2fe78bSCy Schubert CLIENT *h;
133*7f2fe78bSCy Schubert struct ct_data *ct = 0;
134*7f2fe78bSCy Schubert struct timeval now;
135*7f2fe78bSCy Schubert struct rpc_msg call_msg;
136*7f2fe78bSCy Schubert
137*7f2fe78bSCy Schubert h = (CLIENT *)mem_alloc(sizeof(*h));
138*7f2fe78bSCy Schubert if (h == NULL) {
139*7f2fe78bSCy Schubert (void)fprintf(stderr, "clnttcp_create: out of memory\n");
140*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
141*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = errno;
142*7f2fe78bSCy Schubert goto fooy;
143*7f2fe78bSCy Schubert }
144*7f2fe78bSCy Schubert ct = (struct ct_data *)mem_alloc(sizeof(*ct));
145*7f2fe78bSCy Schubert if (ct == NULL) {
146*7f2fe78bSCy Schubert (void)fprintf(stderr, "clnttcp_create: out of memory\n");
147*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
148*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = errno;
149*7f2fe78bSCy Schubert goto fooy;
150*7f2fe78bSCy Schubert }
151*7f2fe78bSCy Schubert
152*7f2fe78bSCy Schubert /*
153*7f2fe78bSCy Schubert * If no port number given ask the pmap for one
154*7f2fe78bSCy Schubert */
155*7f2fe78bSCy Schubert if (raddr != NULL && raddr->sin_port == 0) {
156*7f2fe78bSCy Schubert u_short port;
157*7f2fe78bSCy Schubert if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
158*7f2fe78bSCy Schubert mem_free((caddr_t)ct, sizeof(struct ct_data));
159*7f2fe78bSCy Schubert mem_free((caddr_t)h, sizeof(CLIENT));
160*7f2fe78bSCy Schubert return ((CLIENT *)NULL);
161*7f2fe78bSCy Schubert }
162*7f2fe78bSCy Schubert raddr->sin_port = htons(port);
163*7f2fe78bSCy Schubert }
164*7f2fe78bSCy Schubert
165*7f2fe78bSCy Schubert /*
166*7f2fe78bSCy Schubert * If no socket given, open one
167*7f2fe78bSCy Schubert */
168*7f2fe78bSCy Schubert if (*sockp < 0) {
169*7f2fe78bSCy Schubert *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
170*7f2fe78bSCy Schubert (void)bindresvport_sa(*sockp, NULL);
171*7f2fe78bSCy Schubert if (*sockp < 0 || raddr == NULL ||
172*7f2fe78bSCy Schubert connect(*sockp, (struct sockaddr *)raddr,
173*7f2fe78bSCy Schubert sizeof(*raddr)) < 0) {
174*7f2fe78bSCy Schubert rpc_createerr.cf_stat = RPC_SYSTEMERROR;
175*7f2fe78bSCy Schubert rpc_createerr.cf_error.re_errno = errno;
176*7f2fe78bSCy Schubert (void)closesocket(*sockp);
177*7f2fe78bSCy Schubert goto fooy;
178*7f2fe78bSCy Schubert }
179*7f2fe78bSCy Schubert ct->ct_closeit = TRUE;
180*7f2fe78bSCy Schubert } else {
181*7f2fe78bSCy Schubert ct->ct_closeit = FALSE;
182*7f2fe78bSCy Schubert }
183*7f2fe78bSCy Schubert
184*7f2fe78bSCy Schubert /*
185*7f2fe78bSCy Schubert * Set up private data struct
186*7f2fe78bSCy Schubert */
187*7f2fe78bSCy Schubert ct->ct_sock = *sockp;
188*7f2fe78bSCy Schubert ct->ct_wait.tv_usec = 0;
189*7f2fe78bSCy Schubert ct->ct_waitset = FALSE;
190*7f2fe78bSCy Schubert if (raddr == NULL) {
191*7f2fe78bSCy Schubert /* Get the remote address from the socket, if it's IPv4. */
192*7f2fe78bSCy Schubert struct sockaddr_in sin;
193*7f2fe78bSCy Schubert socklen_t len = sizeof(sin);
194*7f2fe78bSCy Schubert int ret = getpeername(ct->ct_sock, (struct sockaddr *)&sin, &len);
195*7f2fe78bSCy Schubert if (ret == 0 && len == sizeof(sin) && sin.sin_family == AF_INET)
196*7f2fe78bSCy Schubert ct->ct_addr = sin;
197*7f2fe78bSCy Schubert else
198*7f2fe78bSCy Schubert memset(&ct->ct_addr, 0, sizeof(ct->ct_addr));
199*7f2fe78bSCy Schubert } else
200*7f2fe78bSCy Schubert ct->ct_addr = *raddr;
201*7f2fe78bSCy Schubert
202*7f2fe78bSCy Schubert /*
203*7f2fe78bSCy Schubert * Initialize call message
204*7f2fe78bSCy Schubert */
205*7f2fe78bSCy Schubert (void)gettimeofday(&now, (struct timezone *)0);
206*7f2fe78bSCy Schubert call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
207*7f2fe78bSCy Schubert call_msg.rm_direction = CALL;
208*7f2fe78bSCy Schubert call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
209*7f2fe78bSCy Schubert call_msg.rm_call.cb_prog = prog;
210*7f2fe78bSCy Schubert call_msg.rm_call.cb_vers = vers;
211*7f2fe78bSCy Schubert
212*7f2fe78bSCy Schubert /*
213*7f2fe78bSCy Schubert * pre-serialize the staic part of the call msg and stash it away
214*7f2fe78bSCy Schubert */
215*7f2fe78bSCy Schubert xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcall, MCALL_MSG_SIZE,
216*7f2fe78bSCy Schubert XDR_ENCODE);
217*7f2fe78bSCy Schubert if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
218*7f2fe78bSCy Schubert if (ct->ct_closeit)
219*7f2fe78bSCy Schubert (void)closesocket(*sockp);
220*7f2fe78bSCy Schubert goto fooy;
221*7f2fe78bSCy Schubert }
222*7f2fe78bSCy Schubert ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
223*7f2fe78bSCy Schubert XDR_DESTROY(&(ct->ct_xdrs));
224*7f2fe78bSCy Schubert
225*7f2fe78bSCy Schubert /*
226*7f2fe78bSCy Schubert * Create a client handle which uses xdrrec for serialization
227*7f2fe78bSCy Schubert * and authnone for authentication.
228*7f2fe78bSCy Schubert */
229*7f2fe78bSCy Schubert xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
230*7f2fe78bSCy Schubert (caddr_t)ct, readtcp, writetcp);
231*7f2fe78bSCy Schubert h->cl_ops = &tcp_ops;
232*7f2fe78bSCy Schubert h->cl_private = (caddr_t) ct;
233*7f2fe78bSCy Schubert h->cl_auth = authnone_create();
234*7f2fe78bSCy Schubert return (h);
235*7f2fe78bSCy Schubert
236*7f2fe78bSCy Schubert fooy:
237*7f2fe78bSCy Schubert /*
238*7f2fe78bSCy Schubert * Something goofed, free stuff and barf
239*7f2fe78bSCy Schubert */
240*7f2fe78bSCy Schubert mem_free((caddr_t)ct, sizeof(struct ct_data));
241*7f2fe78bSCy Schubert mem_free((caddr_t)h, sizeof(CLIENT));
242*7f2fe78bSCy Schubert return ((CLIENT *)NULL);
243*7f2fe78bSCy Schubert }
244*7f2fe78bSCy Schubert
245*7f2fe78bSCy Schubert static enum clnt_stat
clnttcp_call(CLIENT * h,rpcproc_t proc,xdrproc_t xdr_args,void * args_ptr,xdrproc_t xdr_results,void * results_ptr,struct timeval timeout)246*7f2fe78bSCy Schubert clnttcp_call(
247*7f2fe78bSCy Schubert CLIENT *h,
248*7f2fe78bSCy Schubert rpcproc_t proc,
249*7f2fe78bSCy Schubert xdrproc_t xdr_args,
250*7f2fe78bSCy Schubert void * args_ptr,
251*7f2fe78bSCy Schubert xdrproc_t xdr_results,
252*7f2fe78bSCy Schubert void * results_ptr,
253*7f2fe78bSCy Schubert struct timeval timeout)
254*7f2fe78bSCy Schubert {
255*7f2fe78bSCy Schubert struct ct_data *ct = h->cl_private;
256*7f2fe78bSCy Schubert XDR *xdrs = &ct->ct_xdrs;
257*7f2fe78bSCy Schubert struct rpc_msg reply_msg;
258*7f2fe78bSCy Schubert uint32_t x_id;
259*7f2fe78bSCy Schubert uint32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
260*7f2fe78bSCy Schubert bool_t shipnow;
261*7f2fe78bSCy Schubert int refreshes = 2;
262*7f2fe78bSCy Schubert long procl = proc;
263*7f2fe78bSCy Schubert
264*7f2fe78bSCy Schubert if (!ct->ct_waitset) {
265*7f2fe78bSCy Schubert ct->ct_wait = timeout;
266*7f2fe78bSCy Schubert }
267*7f2fe78bSCy Schubert
268*7f2fe78bSCy Schubert shipnow =
269*7f2fe78bSCy Schubert (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
270*7f2fe78bSCy Schubert && timeout.tv_usec == 0) ? FALSE : TRUE;
271*7f2fe78bSCy Schubert
272*7f2fe78bSCy Schubert call_again:
273*7f2fe78bSCy Schubert xdrs->x_op = XDR_ENCODE;
274*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_SUCCESS;
275*7f2fe78bSCy Schubert x_id = ntohl(--(*msg_x_id));
276*7f2fe78bSCy Schubert if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcall, ct->ct_mpos)) ||
277*7f2fe78bSCy Schubert (! XDR_PUTLONG(xdrs, &procl)) ||
278*7f2fe78bSCy Schubert (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
279*7f2fe78bSCy Schubert (! AUTH_WRAP(h->cl_auth, xdrs, xdr_args, args_ptr))) {
280*7f2fe78bSCy Schubert if (ct->ct_error.re_status == RPC_SUCCESS)
281*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTENCODEARGS;
282*7f2fe78bSCy Schubert (void)xdrrec_endofrecord(xdrs, TRUE);
283*7f2fe78bSCy Schubert return (ct->ct_error.re_status);
284*7f2fe78bSCy Schubert }
285*7f2fe78bSCy Schubert if (! xdrrec_endofrecord(xdrs, shipnow))
286*7f2fe78bSCy Schubert return (ct->ct_error.re_status = RPC_CANTSEND);
287*7f2fe78bSCy Schubert if (! shipnow)
288*7f2fe78bSCy Schubert return (RPC_SUCCESS);
289*7f2fe78bSCy Schubert /*
290*7f2fe78bSCy Schubert * Hack to provide rpc-based message passing
291*7f2fe78bSCy Schubert */
292*7f2fe78bSCy Schubert if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
293*7f2fe78bSCy Schubert return(ct->ct_error.re_status = RPC_TIMEDOUT);
294*7f2fe78bSCy Schubert }
295*7f2fe78bSCy Schubert
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert /*
298*7f2fe78bSCy Schubert * Keep receiving until we get a valid transaction id
299*7f2fe78bSCy Schubert */
300*7f2fe78bSCy Schubert xdrs->x_op = XDR_DECODE;
301*7f2fe78bSCy Schubert while (TRUE) {
302*7f2fe78bSCy Schubert reply_msg.acpted_rply.ar_verf = gssrpc__null_auth;
303*7f2fe78bSCy Schubert reply_msg.acpted_rply.ar_results.where = NULL;
304*7f2fe78bSCy Schubert reply_msg.acpted_rply.ar_results.proc = xdr_void;
305*7f2fe78bSCy Schubert if (! xdrrec_skiprecord(xdrs))
306*7f2fe78bSCy Schubert return (ct->ct_error.re_status);
307*7f2fe78bSCy Schubert /* now decode and validate the response header */
308*7f2fe78bSCy Schubert if (! xdr_replymsg(xdrs, &reply_msg)) {
309*7f2fe78bSCy Schubert /*
310*7f2fe78bSCy Schubert * Free some stuff allocated by xdr_replymsg()
311*7f2fe78bSCy Schubert * to avoid leaks, since it may allocate
312*7f2fe78bSCy Schubert * memory from partially successful decodes.
313*7f2fe78bSCy Schubert */
314*7f2fe78bSCy Schubert enum xdr_op op = xdrs->x_op;
315*7f2fe78bSCy Schubert xdrs->x_op = XDR_FREE;
316*7f2fe78bSCy Schubert xdr_replymsg(xdrs, &reply_msg);
317*7f2fe78bSCy Schubert xdrs->x_op = op;
318*7f2fe78bSCy Schubert if (ct->ct_error.re_status == RPC_SUCCESS)
319*7f2fe78bSCy Schubert continue;
320*7f2fe78bSCy Schubert return (ct->ct_error.re_status);
321*7f2fe78bSCy Schubert }
322*7f2fe78bSCy Schubert if (reply_msg.rm_xid == x_id)
323*7f2fe78bSCy Schubert break;
324*7f2fe78bSCy Schubert }
325*7f2fe78bSCy Schubert
326*7f2fe78bSCy Schubert /*
327*7f2fe78bSCy Schubert * process header
328*7f2fe78bSCy Schubert */
329*7f2fe78bSCy Schubert gssrpc__seterr_reply(&reply_msg, &(ct->ct_error));
330*7f2fe78bSCy Schubert if (ct->ct_error.re_status == RPC_SUCCESS) {
331*7f2fe78bSCy Schubert if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
332*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_AUTHERROR;
333*7f2fe78bSCy Schubert ct->ct_error.re_why = AUTH_INVALIDRESP;
334*7f2fe78bSCy Schubert } else if (! AUTH_UNWRAP(h->cl_auth, xdrs,
335*7f2fe78bSCy Schubert xdr_results, results_ptr)) {
336*7f2fe78bSCy Schubert if (ct->ct_error.re_status == RPC_SUCCESS)
337*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTDECODERES;
338*7f2fe78bSCy Schubert }
339*7f2fe78bSCy Schubert } /* end successful completion */
340*7f2fe78bSCy Schubert else {
341*7f2fe78bSCy Schubert /* maybe our credentials need to be refreshed ... */
342*7f2fe78bSCy Schubert if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
343*7f2fe78bSCy Schubert goto call_again;
344*7f2fe78bSCy Schubert } /* end of unsuccessful completion */
345*7f2fe78bSCy Schubert /* free verifier ... */
346*7f2fe78bSCy Schubert if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
347*7f2fe78bSCy Schubert (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) {
348*7f2fe78bSCy Schubert xdrs->x_op = XDR_FREE;
349*7f2fe78bSCy Schubert (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
350*7f2fe78bSCy Schubert }
351*7f2fe78bSCy Schubert return (ct->ct_error.re_status);
352*7f2fe78bSCy Schubert }
353*7f2fe78bSCy Schubert
354*7f2fe78bSCy Schubert static void
clnttcp_geterr(CLIENT * h,struct rpc_err * errp)355*7f2fe78bSCy Schubert clnttcp_geterr(
356*7f2fe78bSCy Schubert CLIENT *h,
357*7f2fe78bSCy Schubert struct rpc_err *errp)
358*7f2fe78bSCy Schubert {
359*7f2fe78bSCy Schubert struct ct_data *ct = h->cl_private;
360*7f2fe78bSCy Schubert
361*7f2fe78bSCy Schubert *errp = ct->ct_error;
362*7f2fe78bSCy Schubert }
363*7f2fe78bSCy Schubert
364*7f2fe78bSCy Schubert static bool_t
clnttcp_freeres(CLIENT * cl,xdrproc_t xdr_res,void * res_ptr)365*7f2fe78bSCy Schubert clnttcp_freeres(
366*7f2fe78bSCy Schubert CLIENT *cl,
367*7f2fe78bSCy Schubert xdrproc_t xdr_res,
368*7f2fe78bSCy Schubert void * res_ptr)
369*7f2fe78bSCy Schubert {
370*7f2fe78bSCy Schubert struct ct_data *ct = cl->cl_private;
371*7f2fe78bSCy Schubert XDR *xdrs = &ct->ct_xdrs;
372*7f2fe78bSCy Schubert
373*7f2fe78bSCy Schubert xdrs->x_op = XDR_FREE;
374*7f2fe78bSCy Schubert return ((*xdr_res)(xdrs, res_ptr));
375*7f2fe78bSCy Schubert }
376*7f2fe78bSCy Schubert
377*7f2fe78bSCy Schubert /*ARGSUSED*/
378*7f2fe78bSCy Schubert static void
clnttcp_abort(CLIENT * cl)379*7f2fe78bSCy Schubert clnttcp_abort(CLIENT *cl)
380*7f2fe78bSCy Schubert {
381*7f2fe78bSCy Schubert }
382*7f2fe78bSCy Schubert
383*7f2fe78bSCy Schubert static bool_t
clnttcp_control(CLIENT * cl,int request,void * info)384*7f2fe78bSCy Schubert clnttcp_control(
385*7f2fe78bSCy Schubert CLIENT *cl,
386*7f2fe78bSCy Schubert int request,
387*7f2fe78bSCy Schubert void *info)
388*7f2fe78bSCy Schubert {
389*7f2fe78bSCy Schubert struct ct_data *ct = cl->cl_private;
390*7f2fe78bSCy Schubert GETSOCKNAME_ARG3_TYPE len;
391*7f2fe78bSCy Schubert
392*7f2fe78bSCy Schubert switch (request) {
393*7f2fe78bSCy Schubert case CLSET_TIMEOUT:
394*7f2fe78bSCy Schubert ct->ct_wait = *(struct timeval *)info;
395*7f2fe78bSCy Schubert ct->ct_waitset = TRUE;
396*7f2fe78bSCy Schubert break;
397*7f2fe78bSCy Schubert case CLGET_TIMEOUT:
398*7f2fe78bSCy Schubert *(struct timeval *)info = ct->ct_wait;
399*7f2fe78bSCy Schubert break;
400*7f2fe78bSCy Schubert case CLGET_SERVER_ADDR:
401*7f2fe78bSCy Schubert *(struct sockaddr_in *)info = ct->ct_addr;
402*7f2fe78bSCy Schubert break;
403*7f2fe78bSCy Schubert case CLGET_LOCAL_ADDR:
404*7f2fe78bSCy Schubert len = sizeof(struct sockaddr);
405*7f2fe78bSCy Schubert if (getsockname(ct->ct_sock, (struct sockaddr*)info, &len) < 0)
406*7f2fe78bSCy Schubert return FALSE;
407*7f2fe78bSCy Schubert else
408*7f2fe78bSCy Schubert return TRUE;
409*7f2fe78bSCy Schubert default:
410*7f2fe78bSCy Schubert return (FALSE);
411*7f2fe78bSCy Schubert }
412*7f2fe78bSCy Schubert return (TRUE);
413*7f2fe78bSCy Schubert }
414*7f2fe78bSCy Schubert
415*7f2fe78bSCy Schubert
416*7f2fe78bSCy Schubert static void
clnttcp_destroy(CLIENT * h)417*7f2fe78bSCy Schubert clnttcp_destroy(CLIENT *h)
418*7f2fe78bSCy Schubert {
419*7f2fe78bSCy Schubert struct ct_data *ct = h->cl_private;
420*7f2fe78bSCy Schubert
421*7f2fe78bSCy Schubert if (ct->ct_closeit)
422*7f2fe78bSCy Schubert (void)closesocket(ct->ct_sock);
423*7f2fe78bSCy Schubert XDR_DESTROY(&(ct->ct_xdrs));
424*7f2fe78bSCy Schubert mem_free((caddr_t)ct, sizeof(struct ct_data));
425*7f2fe78bSCy Schubert mem_free((caddr_t)h, sizeof(CLIENT));
426*7f2fe78bSCy Schubert }
427*7f2fe78bSCy Schubert
428*7f2fe78bSCy Schubert /*
429*7f2fe78bSCy Schubert * Interface between xdr serializer and tcp connection.
430*7f2fe78bSCy Schubert * Behaves like the system calls, read & write, but keeps some error state
431*7f2fe78bSCy Schubert * around for the rpc level.
432*7f2fe78bSCy Schubert */
433*7f2fe78bSCy Schubert static int
readtcp(char * ctptr,caddr_t buf,int len)434*7f2fe78bSCy Schubert readtcp(
435*7f2fe78bSCy Schubert char *ctptr,
436*7f2fe78bSCy Schubert caddr_t buf,
437*7f2fe78bSCy Schubert int len)
438*7f2fe78bSCy Schubert {
439*7f2fe78bSCy Schubert struct ct_data *ct = (void *)ctptr;
440*7f2fe78bSCy Schubert struct timeval tout;
441*7f2fe78bSCy Schubert #ifdef FD_SETSIZE
442*7f2fe78bSCy Schubert fd_set mask;
443*7f2fe78bSCy Schubert fd_set readfds;
444*7f2fe78bSCy Schubert
445*7f2fe78bSCy Schubert if (len == 0)
446*7f2fe78bSCy Schubert return (0);
447*7f2fe78bSCy Schubert FD_ZERO(&mask);
448*7f2fe78bSCy Schubert FD_SET(ct->ct_sock, &mask);
449*7f2fe78bSCy Schubert #else
450*7f2fe78bSCy Schubert int mask = 1 << (ct->ct_sock);
451*7f2fe78bSCy Schubert int readfds;
452*7f2fe78bSCy Schubert
453*7f2fe78bSCy Schubert if (len == 0)
454*7f2fe78bSCy Schubert return (0);
455*7f2fe78bSCy Schubert
456*7f2fe78bSCy Schubert #endif /* def FD_SETSIZE */
457*7f2fe78bSCy Schubert while (TRUE) {
458*7f2fe78bSCy Schubert readfds = mask;
459*7f2fe78bSCy Schubert tout = ct->ct_wait;
460*7f2fe78bSCy Schubert switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set*)NULL, (fd_set*)NULL,
461*7f2fe78bSCy Schubert &tout)) {
462*7f2fe78bSCy Schubert case 0:
463*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_TIMEDOUT;
464*7f2fe78bSCy Schubert return (-1);
465*7f2fe78bSCy Schubert
466*7f2fe78bSCy Schubert case -1:
467*7f2fe78bSCy Schubert if (errno == EINTR)
468*7f2fe78bSCy Schubert continue;
469*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTRECV;
470*7f2fe78bSCy Schubert ct->ct_error.re_errno = errno;
471*7f2fe78bSCy Schubert return (-1);
472*7f2fe78bSCy Schubert }
473*7f2fe78bSCy Schubert break;
474*7f2fe78bSCy Schubert }
475*7f2fe78bSCy Schubert switch (len = read(ct->ct_sock, buf, (size_t) len)) {
476*7f2fe78bSCy Schubert
477*7f2fe78bSCy Schubert case 0:
478*7f2fe78bSCy Schubert /* premature eof */
479*7f2fe78bSCy Schubert ct->ct_error.re_errno = ECONNRESET;
480*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTRECV;
481*7f2fe78bSCy Schubert len = -1; /* it's really an error */
482*7f2fe78bSCy Schubert break;
483*7f2fe78bSCy Schubert
484*7f2fe78bSCy Schubert case -1:
485*7f2fe78bSCy Schubert ct->ct_error.re_errno = errno;
486*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTRECV;
487*7f2fe78bSCy Schubert break;
488*7f2fe78bSCy Schubert }
489*7f2fe78bSCy Schubert return (len);
490*7f2fe78bSCy Schubert }
491*7f2fe78bSCy Schubert
492*7f2fe78bSCy Schubert static int
writetcp(char * ctptr,caddr_t buf,int len)493*7f2fe78bSCy Schubert writetcp(
494*7f2fe78bSCy Schubert char *ctptr,
495*7f2fe78bSCy Schubert caddr_t buf,
496*7f2fe78bSCy Schubert int len)
497*7f2fe78bSCy Schubert {
498*7f2fe78bSCy Schubert struct ct_data *ct = (struct ct_data *)(void *)ctptr;
499*7f2fe78bSCy Schubert int i, cnt;
500*7f2fe78bSCy Schubert
501*7f2fe78bSCy Schubert for (cnt = len; cnt > 0; cnt -= i, buf += i) {
502*7f2fe78bSCy Schubert if ((i = write(ct->ct_sock, buf, (size_t) cnt)) == -1) {
503*7f2fe78bSCy Schubert ct->ct_error.re_errno = errno;
504*7f2fe78bSCy Schubert ct->ct_error.re_status = RPC_CANTSEND;
505*7f2fe78bSCy Schubert return (-1);
506*7f2fe78bSCy Schubert }
507*7f2fe78bSCy Schubert }
508*7f2fe78bSCy Schubert return (len);
509*7f2fe78bSCy Schubert }
510