xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c (revision 8334:5f1c6a3b0fad)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
27*8334SJose.Borrego@Sun.COM  * Client NDR RPC interface.
285331Samw  */
295331Samw 
305331Samw #include <sys/errno.h>
315331Samw #include <strings.h>
32*8334SJose.Borrego@Sun.COM #include <assert.h>
335331Samw #include <smbsrv/libsmb.h>
345331Samw #include <smbsrv/libsmbrdr.h>
35*8334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
36*8334SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h>
375331Samw 
38*8334SJose.Borrego@Sun.COM static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
39*8334SJose.Borrego@Sun.COM static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
40*8334SJose.Borrego@Sun.COM static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
41*8334SJose.Borrego@Sun.COM static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
42*8334SJose.Borrego@Sun.COM static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
43*8334SJose.Borrego@Sun.COM static void ndr_xa_release(ndr_client_t *);
445331Samw 
455331Samw /*
46*8334SJose.Borrego@Sun.COM  * This call must be made to initialize an RPC client structure and bind
47*8334SJose.Borrego@Sun.COM  * to the remote service before any RPCs can be exchanged with that service.
485331Samw  *
49*8334SJose.Borrego@Sun.COM  * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
50*8334SJose.Borrego@Sun.COM  * with the client context for an instance of the interface.  The handle
51*8334SJose.Borrego@Sun.COM  * is zeroed to ensure that it doesn't look like a valid handle -
52*8334SJose.Borrego@Sun.COM  * handle content is provided by the remove service.
535331Samw  *
54*8334SJose.Borrego@Sun.COM  * The client points to this top-level handle so that we know when to
55*8334SJose.Borrego@Sun.COM  * unbind and teardown the connection.  As each handle is initialized it
56*8334SJose.Borrego@Sun.COM  * will inherit a reference to the client context.
575331Samw  */
585331Samw int
59*8334SJose.Borrego@Sun.COM ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
60*8334SJose.Borrego@Sun.COM     char *username, const char *service)
615331Samw {
62*8334SJose.Borrego@Sun.COM 	ndr_client_t		*clnt;
63*8334SJose.Borrego@Sun.COM 	ndr_service_t		*svc;
64*8334SJose.Borrego@Sun.COM 	smbrdr_session_info_t	si;
65*8334SJose.Borrego@Sun.COM 	int			fid;
66*8334SJose.Borrego@Sun.COM 	int			rc;
675331Samw 
68*8334SJose.Borrego@Sun.COM 	if (handle == NULL || server == NULL ||
69*8334SJose.Borrego@Sun.COM 	    domain == NULL || username == NULL)
705331Samw 		return (-1);
715331Samw 
72*8334SJose.Borrego@Sun.COM 	if ((svc = ndr_svc_lookup_name(service)) == NULL)
73*8334SJose.Borrego@Sun.COM 		return (-1);
745331Samw 
75*8334SJose.Borrego@Sun.COM 	if ((clnt = malloc(sizeof (ndr_client_t))) == NULL)
76*8334SJose.Borrego@Sun.COM 		return (-1);
775331Samw 
78*8334SJose.Borrego@Sun.COM 	fid = smbrdr_open_pipe(server, domain, username, svc->endpoint);
79*8334SJose.Borrego@Sun.COM 	if (fid < 0) {
80*8334SJose.Borrego@Sun.COM 		free(clnt);
815331Samw 		return (-1);
825331Samw 	}
835331Samw 
84*8334SJose.Borrego@Sun.COM 	bzero(clnt, sizeof (ndr_client_t));
85*8334SJose.Borrego@Sun.COM 	clnt->handle = &handle->handle;
86*8334SJose.Borrego@Sun.COM 	clnt->fid = fid;
87*8334SJose.Borrego@Sun.COM 
88*8334SJose.Borrego@Sun.COM 	ndr_svc_binding_pool_init(&clnt->binding_list,
89*8334SJose.Borrego@Sun.COM 	    clnt->binding_pool, NDR_N_BINDING_POOL);
90*8334SJose.Borrego@Sun.COM 
91*8334SJose.Borrego@Sun.COM 	clnt->xa_init = ndr_xa_init;
92*8334SJose.Borrego@Sun.COM 	clnt->xa_exchange = ndr_xa_exchange;
93*8334SJose.Borrego@Sun.COM 	clnt->xa_read = ndr_xa_read;
94*8334SJose.Borrego@Sun.COM 	clnt->xa_preserve = ndr_xa_preserve;
95*8334SJose.Borrego@Sun.COM 	clnt->xa_destruct = ndr_xa_destruct;
96*8334SJose.Borrego@Sun.COM 	clnt->xa_release = ndr_xa_release;
975331Samw 
98*8334SJose.Borrego@Sun.COM 	(void) smbrdr_session_info(fid, &si);
99*8334SJose.Borrego@Sun.COM 	bzero(&handle->handle, sizeof (ndr_hdid_t));
100*8334SJose.Borrego@Sun.COM 	handle->clnt = clnt;
101*8334SJose.Borrego@Sun.COM 	handle->remote_os = si.si_server_os;
1025331Samw 
103*8334SJose.Borrego@Sun.COM 	if (ndr_rpc_get_heap(handle) == NULL) {
104*8334SJose.Borrego@Sun.COM 		free(clnt);
1055331Samw 		return (-1);
106*8334SJose.Borrego@Sun.COM 	}
107*8334SJose.Borrego@Sun.COM 
108*8334SJose.Borrego@Sun.COM 	rc = ndr_clnt_bind(clnt, service, &clnt->binding);
109*8334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
110*8334SJose.Borrego@Sun.COM 		(void) smbrdr_close_pipe(fid);
111*8334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
112*8334SJose.Borrego@Sun.COM 		free(clnt);
113*8334SJose.Borrego@Sun.COM 		handle->clnt = NULL;
114*8334SJose.Borrego@Sun.COM 		return (-1);
115*8334SJose.Borrego@Sun.COM 	}
1165331Samw 
1175331Samw 	return (0);
1185331Samw }
1195331Samw 
1205331Samw /*
121*8334SJose.Borrego@Sun.COM  * Unbind and close the pipe to an RPC service.
122*8334SJose.Borrego@Sun.COM  *
123*8334SJose.Borrego@Sun.COM  * If the heap has been preserved we need to go through an xa release.
124*8334SJose.Borrego@Sun.COM  * The heap is preserved during an RPC call because that's where data
125*8334SJose.Borrego@Sun.COM  * returned from the server is stored.
1265331Samw  *
127*8334SJose.Borrego@Sun.COM  * Otherwise we destroy the heap directly.
128*8334SJose.Borrego@Sun.COM  */
129*8334SJose.Borrego@Sun.COM void
130*8334SJose.Borrego@Sun.COM ndr_rpc_unbind(mlsvc_handle_t *handle)
131*8334SJose.Borrego@Sun.COM {
132*8334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
133*8334SJose.Borrego@Sun.COM 
134*8334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved)
135*8334SJose.Borrego@Sun.COM 		ndr_clnt_free_heap(clnt);
136*8334SJose.Borrego@Sun.COM 	else
137*8334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
138*8334SJose.Borrego@Sun.COM 
139*8334SJose.Borrego@Sun.COM 	(void) smbrdr_close_pipe(clnt->fid);
140*8334SJose.Borrego@Sun.COM 	free(handle->clnt);
141*8334SJose.Borrego@Sun.COM 	bzero(handle, sizeof (mlsvc_handle_t));
142*8334SJose.Borrego@Sun.COM }
143*8334SJose.Borrego@Sun.COM 
144*8334SJose.Borrego@Sun.COM /*
145*8334SJose.Borrego@Sun.COM  * Call the RPC function identified by opnum.  The remote service is
146*8334SJose.Borrego@Sun.COM  * identified by the handle, which should have been initialized by
147*8334SJose.Borrego@Sun.COM  * ndr_rpc_bind.
148*8334SJose.Borrego@Sun.COM  *
149*8334SJose.Borrego@Sun.COM  * If the RPC call is successful (returns 0), the caller must call
150*8334SJose.Borrego@Sun.COM  * ndr_rpc_release to release the heap.  Otherwise, we release the
151*8334SJose.Borrego@Sun.COM  * heap here.
1525331Samw  */
1535331Samw int
154*8334SJose.Borrego@Sun.COM ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
155*8334SJose.Borrego@Sun.COM {
156*8334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
157*8334SJose.Borrego@Sun.COM 	int rc;
158*8334SJose.Borrego@Sun.COM 
159*8334SJose.Borrego@Sun.COM 	if (ndr_rpc_get_heap(handle) == NULL)
160*8334SJose.Borrego@Sun.COM 		return (-1);
161*8334SJose.Borrego@Sun.COM 
162*8334SJose.Borrego@Sun.COM 	rc = ndr_clnt_call(clnt->binding, opnum, params);
163*8334SJose.Borrego@Sun.COM 
164*8334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
165*8334SJose.Borrego@Sun.COM 		ndr_rpc_release(handle);
166*8334SJose.Borrego@Sun.COM 		return (-1);
167*8334SJose.Borrego@Sun.COM 	}
168*8334SJose.Borrego@Sun.COM 
169*8334SJose.Borrego@Sun.COM 	return (0);
170*8334SJose.Borrego@Sun.COM }
171*8334SJose.Borrego@Sun.COM 
172*8334SJose.Borrego@Sun.COM /*
173*8334SJose.Borrego@Sun.COM  * Returns the Native-OS of the RPC server.
174*8334SJose.Borrego@Sun.COM  */
175*8334SJose.Borrego@Sun.COM int
176*8334SJose.Borrego@Sun.COM ndr_rpc_server_os(mlsvc_handle_t *handle)
1775331Samw {
178*8334SJose.Borrego@Sun.COM 	return (handle->remote_os);
179*8334SJose.Borrego@Sun.COM }
180*8334SJose.Borrego@Sun.COM 
181*8334SJose.Borrego@Sun.COM void *
182*8334SJose.Borrego@Sun.COM ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
183*8334SJose.Borrego@Sun.COM {
184*8334SJose.Borrego@Sun.COM 	ndr_heap_t *heap;
185*8334SJose.Borrego@Sun.COM 
186*8334SJose.Borrego@Sun.COM 	if ((heap = ndr_rpc_get_heap(handle)) == NULL)
187*8334SJose.Borrego@Sun.COM 		return (NULL);
188*8334SJose.Borrego@Sun.COM 
189*8334SJose.Borrego@Sun.COM 	return (ndr_heap_malloc(heap, size));
190*8334SJose.Borrego@Sun.COM }
191*8334SJose.Borrego@Sun.COM 
192*8334SJose.Borrego@Sun.COM ndr_heap_t *
193*8334SJose.Borrego@Sun.COM ndr_rpc_get_heap(mlsvc_handle_t *handle)
194*8334SJose.Borrego@Sun.COM {
195*8334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
196*8334SJose.Borrego@Sun.COM 
197*8334SJose.Borrego@Sun.COM 	if (clnt->heap == NULL)
198*8334SJose.Borrego@Sun.COM 		clnt->heap = ndr_heap_create();
199*8334SJose.Borrego@Sun.COM 
200*8334SJose.Borrego@Sun.COM 	return (clnt->heap);
2015331Samw }
2025331Samw 
2035331Samw /*
204*8334SJose.Borrego@Sun.COM  * Must be called by RPC clients to free the heap after a successful RPC
205*8334SJose.Borrego@Sun.COM  * call, i.e. ndr_rpc_call returned 0.  The caller should take a copy
206*8334SJose.Borrego@Sun.COM  * of any data returned by the RPC prior to calling this function because
207*8334SJose.Borrego@Sun.COM  * returned data is in the heap.
2085331Samw  */
2095331Samw void
210*8334SJose.Borrego@Sun.COM ndr_rpc_release(mlsvc_handle_t *handle)
211*8334SJose.Borrego@Sun.COM {
212*8334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
213*8334SJose.Borrego@Sun.COM 
214*8334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved)
215*8334SJose.Borrego@Sun.COM 		ndr_clnt_free_heap(clnt);
216*8334SJose.Borrego@Sun.COM 	else
217*8334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
218*8334SJose.Borrego@Sun.COM 
219*8334SJose.Borrego@Sun.COM 	clnt->heap = NULL;
220*8334SJose.Borrego@Sun.COM }
221*8334SJose.Borrego@Sun.COM 
222*8334SJose.Borrego@Sun.COM /*
223*8334SJose.Borrego@Sun.COM  * Returns true if the handle is null.
224*8334SJose.Borrego@Sun.COM  * Otherwise returns false.
225*8334SJose.Borrego@Sun.COM  */
226*8334SJose.Borrego@Sun.COM boolean_t
227*8334SJose.Borrego@Sun.COM ndr_is_null_handle(mlsvc_handle_t *handle)
2285331Samw {
229*8334SJose.Borrego@Sun.COM 	static ndr_hdid_t zero_handle;
230*8334SJose.Borrego@Sun.COM 
231*8334SJose.Borrego@Sun.COM 	if (handle == NULL || handle->clnt == NULL)
232*8334SJose.Borrego@Sun.COM 		return (B_TRUE);
233*8334SJose.Borrego@Sun.COM 
234*8334SJose.Borrego@Sun.COM 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
235*8334SJose.Borrego@Sun.COM 		return (B_TRUE);
236*8334SJose.Borrego@Sun.COM 
237*8334SJose.Borrego@Sun.COM 	return (B_FALSE);
238*8334SJose.Borrego@Sun.COM }
239*8334SJose.Borrego@Sun.COM 
240*8334SJose.Borrego@Sun.COM /*
241*8334SJose.Borrego@Sun.COM  * Returns true if the handle is the top level bind handle.
242*8334SJose.Borrego@Sun.COM  * Otherwise returns false.
243*8334SJose.Borrego@Sun.COM  */
244*8334SJose.Borrego@Sun.COM boolean_t
245*8334SJose.Borrego@Sun.COM ndr_is_bind_handle(mlsvc_handle_t *handle)
246*8334SJose.Borrego@Sun.COM {
247*8334SJose.Borrego@Sun.COM 	return (handle->clnt->handle == &handle->handle);
2485331Samw }
2495331Samw 
2505331Samw /*
251*8334SJose.Borrego@Sun.COM  * Pass the client reference from parent to child.
2525331Samw  */
253*8334SJose.Borrego@Sun.COM void
254*8334SJose.Borrego@Sun.COM ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
255*8334SJose.Borrego@Sun.COM {
256*8334SJose.Borrego@Sun.COM 	child->clnt = parent->clnt;
257*8334SJose.Borrego@Sun.COM 	child->remote_os = parent->remote_os;
258*8334SJose.Borrego@Sun.COM }
259*8334SJose.Borrego@Sun.COM 
260*8334SJose.Borrego@Sun.COM void
261*8334SJose.Borrego@Sun.COM ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
2625331Samw {
263*8334SJose.Borrego@Sun.COM 	ndr_service_t *svc;
264*8334SJose.Borrego@Sun.COM 	char *name = "NDR RPC";
265*8334SJose.Borrego@Sun.COM 	char *s = "unknown";
266*8334SJose.Borrego@Sun.COM 
267*8334SJose.Borrego@Sun.COM 	if (status == 0)
268*8334SJose.Borrego@Sun.COM 		s = "success";
269*8334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_ERROR(status))
270*8334SJose.Borrego@Sun.COM 		s = "error";
271*8334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_WARNING(status))
272*8334SJose.Borrego@Sun.COM 		s = "warning";
273*8334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_INFO(status))
274*8334SJose.Borrego@Sun.COM 		s = "info";
275*8334SJose.Borrego@Sun.COM 
276*8334SJose.Borrego@Sun.COM 	if (handle) {
277*8334SJose.Borrego@Sun.COM 		svc = handle->clnt->binding->service;
278*8334SJose.Borrego@Sun.COM 		name = svc->name;
279*8334SJose.Borrego@Sun.COM 	}
2805331Samw 
281*8334SJose.Borrego@Sun.COM 	smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
282*8334SJose.Borrego@Sun.COM 	    name, opnum, s, xlate_nt_status(status), status);
283*8334SJose.Borrego@Sun.COM }
284*8334SJose.Borrego@Sun.COM 
285*8334SJose.Borrego@Sun.COM /*
286*8334SJose.Borrego@Sun.COM  * The following functions provide the client callback interface.
287*8334SJose.Borrego@Sun.COM  * If the caller hasn't provided a heap, create one here.
288*8334SJose.Borrego@Sun.COM  */
289*8334SJose.Borrego@Sun.COM static int
290*8334SJose.Borrego@Sun.COM ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
291*8334SJose.Borrego@Sun.COM {
292*8334SJose.Borrego@Sun.COM 	ndr_stream_t *recv_nds = &mxa->recv_nds;
293*8334SJose.Borrego@Sun.COM 	ndr_stream_t *send_nds = &mxa->send_nds;
294*8334SJose.Borrego@Sun.COM 	ndr_heap_t *heap = clnt->heap;
295*8334SJose.Borrego@Sun.COM 
296*8334SJose.Borrego@Sun.COM 	if (heap == NULL) {
297*8334SJose.Borrego@Sun.COM 		if ((heap = ndr_heap_create()) == NULL)
2985331Samw 			return (-1);
299*8334SJose.Borrego@Sun.COM 
300*8334SJose.Borrego@Sun.COM 		clnt->heap = heap;
3015331Samw 	}
3025331Samw 
3035331Samw 	mxa->heap = heap;
3045331Samw 
305*8334SJose.Borrego@Sun.COM 	nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
306*8334SJose.Borrego@Sun.COM 	nds_initialize(recv_nds, 16 * 1024, NDR_MODE_RETURN_RECV, heap);
3075331Samw 	return (0);
3085331Samw }
3095331Samw 
3105331Samw /*
3115331Samw  * This is the entry pointy for an RPC client call exchange with
3125331Samw  * a server, which will result in an smbrdr SmbTransact request.
3135331Samw  *
3145331Samw  * SmbTransact should return the number of bytes received, which
3155331Samw  * we record as the PDU size, or a negative error code.
3165331Samw  */
3175331Samw static int
318*8334SJose.Borrego@Sun.COM ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
3195331Samw {
320*8334SJose.Borrego@Sun.COM 	ndr_stream_t *recv_nds = &mxa->recv_nds;
321*8334SJose.Borrego@Sun.COM 	ndr_stream_t *send_nds = &mxa->send_nds;
322*8334SJose.Borrego@Sun.COM 	int nbytes;
3235331Samw 
324*8334SJose.Borrego@Sun.COM 	nbytes = smbrdr_transact(clnt->fid,
325*8334SJose.Borrego@Sun.COM 	    (char *)send_nds->pdu_base_offset, send_nds->pdu_size,
326*8334SJose.Borrego@Sun.COM 	    (char *)recv_nds->pdu_base_offset, recv_nds->pdu_max_size);
3275331Samw 
328*8334SJose.Borrego@Sun.COM 	if (nbytes < 0) {
329*8334SJose.Borrego@Sun.COM 		recv_nds->pdu_size = 0;
330*8334SJose.Borrego@Sun.COM 		return (-1);
331*8334SJose.Borrego@Sun.COM 	}
3325331Samw 
333*8334SJose.Borrego@Sun.COM 	recv_nds->pdu_size = nbytes;
334*8334SJose.Borrego@Sun.COM 	return (nbytes);
3355331Samw }
3365331Samw 
3375331Samw /*
3385331Samw  * This entry point will be invoked if the xa-exchange response contained
3395331Samw  * only the first fragment of a multi-fragment response.  The RPC client
3405331Samw  * code will then make repeated xa-read requests to obtain the remaining
3415331Samw  * fragments, which will result in smbrdr SmbReadX requests.
3425331Samw  *
3435331Samw  * SmbReadX should return the number of bytes received, in which case we
3445331Samw  * expand the PDU size to include the received data, or a negative error
3455331Samw  * code.
3465331Samw  */
3475331Samw static int
348*8334SJose.Borrego@Sun.COM ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
3495331Samw {
350*8334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->recv_nds;
3515331Samw 	int len;
352*8334SJose.Borrego@Sun.COM 	int nbytes;
3535331Samw 
354*8334SJose.Borrego@Sun.COM 	if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
3555331Samw 		return (-1);
3565331Samw 
357*8334SJose.Borrego@Sun.COM 	nbytes = smbrdr_readx(clnt->fid,
358*8334SJose.Borrego@Sun.COM 	    (char *)nds->pdu_base_offset + nds->pdu_size, len);
3595331Samw 
360*8334SJose.Borrego@Sun.COM 	if (nbytes < 0)
3615331Samw 		return (-1);
3625331Samw 
363*8334SJose.Borrego@Sun.COM 	nds->pdu_size += nbytes;
3645331Samw 
365*8334SJose.Borrego@Sun.COM 	if (nds->pdu_size > nds->pdu_max_size) {
366*8334SJose.Borrego@Sun.COM 		nds->pdu_size = nds->pdu_max_size;
3675331Samw 		return (-1);
3685331Samw 	}
3695331Samw 
370*8334SJose.Borrego@Sun.COM 	return (nbytes);
3715331Samw }
3725331Samw 
3735331Samw /*
374*8334SJose.Borrego@Sun.COM  * Preserve the heap so that the client application has access to data
375*8334SJose.Borrego@Sun.COM  * returned from the server after an RPC call.
3765331Samw  */
377*8334SJose.Borrego@Sun.COM static void
378*8334SJose.Borrego@Sun.COM ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
3795331Samw {
380*8334SJose.Borrego@Sun.COM 	assert(clnt->heap == mxa->heap);
3815331Samw 
382*8334SJose.Borrego@Sun.COM 	clnt->heap_preserved = B_TRUE;
3835331Samw 	mxa->heap = NULL;
3845331Samw }
3855331Samw 
3865331Samw /*
387*8334SJose.Borrego@Sun.COM  * Dispose of the transaction streams.  If the heap has not been
388*8334SJose.Borrego@Sun.COM  * preserved, we can destroy it here.
3895331Samw  */
390*8334SJose.Borrego@Sun.COM static void
391*8334SJose.Borrego@Sun.COM ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
3925331Samw {
393*8334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->recv_nds);
394*8334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->send_nds);
395*8334SJose.Borrego@Sun.COM 
396*8334SJose.Borrego@Sun.COM 	if (!clnt->heap_preserved) {
397*8334SJose.Borrego@Sun.COM 		ndr_heap_destroy(mxa->heap);
398*8334SJose.Borrego@Sun.COM 		mxa->heap = NULL;
399*8334SJose.Borrego@Sun.COM 		clnt->heap = NULL;
4005331Samw 	}
4015331Samw }
4025331Samw 
4035331Samw /*
404*8334SJose.Borrego@Sun.COM  * Dispose of a preserved heap.
4055331Samw  */
4065331Samw static void
407*8334SJose.Borrego@Sun.COM ndr_xa_release(ndr_client_t *clnt)
4085331Samw {
409*8334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved) {
410*8334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
411*8334SJose.Borrego@Sun.COM 		clnt->heap = NULL;
412*8334SJose.Borrego@Sun.COM 		clnt->heap_preserved = B_FALSE;
4135331Samw 	}
4145331Samw }
415