xref: /freebsd/crypto/krb5/src/lib/rpc/clnt_tcp.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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