xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c (revision 10504:ee04788f8605)
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 /*
229914Samw@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
278334SJose.Borrego@Sun.COM  * Client NDR RPC interface.
285331Samw  */
295331Samw 
305331Samw #include <sys/errno.h>
315331Samw #include <strings.h>
328334SJose.Borrego@Sun.COM #include <assert.h>
335331Samw #include <smbsrv/libsmb.h>
345331Samw #include <smbsrv/libsmbrdr.h>
358334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
368334SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h>
375331Samw 
388334SJose.Borrego@Sun.COM static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
398334SJose.Borrego@Sun.COM static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
408334SJose.Borrego@Sun.COM static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
418334SJose.Borrego@Sun.COM static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
428334SJose.Borrego@Sun.COM static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
438334SJose.Borrego@Sun.COM static void ndr_xa_release(ndr_client_t *);
445331Samw 
455331Samw /*
468334SJose.Borrego@Sun.COM  * This call must be made to initialize an RPC client structure and bind
478334SJose.Borrego@Sun.COM  * to the remote service before any RPCs can be exchanged with that service.
485331Samw  *
498334SJose.Borrego@Sun.COM  * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
508334SJose.Borrego@Sun.COM  * with the client context for an instance of the interface.  The handle
518334SJose.Borrego@Sun.COM  * is zeroed to ensure that it doesn't look like a valid handle -
528334SJose.Borrego@Sun.COM  * handle content is provided by the remove service.
535331Samw  *
548334SJose.Borrego@Sun.COM  * The client points to this top-level handle so that we know when to
558334SJose.Borrego@Sun.COM  * unbind and teardown the connection.  As each handle is initialized it
568334SJose.Borrego@Sun.COM  * will inherit a reference to the client context.
575331Samw  */
585331Samw int
598334SJose.Borrego@Sun.COM ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
608334SJose.Borrego@Sun.COM     char *username, const char *service)
615331Samw {
628334SJose.Borrego@Sun.COM 	ndr_client_t		*clnt;
638334SJose.Borrego@Sun.COM 	ndr_service_t		*svc;
648334SJose.Borrego@Sun.COM 	smbrdr_session_info_t	si;
658334SJose.Borrego@Sun.COM 	int			fid;
668334SJose.Borrego@Sun.COM 	int			rc;
675331Samw 
688334SJose.Borrego@Sun.COM 	if (handle == NULL || server == NULL ||
698334SJose.Borrego@Sun.COM 	    domain == NULL || username == NULL)
705331Samw 		return (-1);
715331Samw 
728334SJose.Borrego@Sun.COM 	if ((svc = ndr_svc_lookup_name(service)) == NULL)
738334SJose.Borrego@Sun.COM 		return (-1);
745331Samw 
758334SJose.Borrego@Sun.COM 	if ((clnt = malloc(sizeof (ndr_client_t))) == NULL)
768334SJose.Borrego@Sun.COM 		return (-1);
775331Samw 
788334SJose.Borrego@Sun.COM 	fid = smbrdr_open_pipe(server, domain, username, svc->endpoint);
798334SJose.Borrego@Sun.COM 	if (fid < 0) {
808334SJose.Borrego@Sun.COM 		free(clnt);
815331Samw 		return (-1);
825331Samw 	}
835331Samw 
848334SJose.Borrego@Sun.COM 	bzero(clnt, sizeof (ndr_client_t));
858334SJose.Borrego@Sun.COM 	clnt->handle = &handle->handle;
868334SJose.Borrego@Sun.COM 	clnt->fid = fid;
878334SJose.Borrego@Sun.COM 
888334SJose.Borrego@Sun.COM 	ndr_svc_binding_pool_init(&clnt->binding_list,
898334SJose.Borrego@Sun.COM 	    clnt->binding_pool, NDR_N_BINDING_POOL);
908334SJose.Borrego@Sun.COM 
918334SJose.Borrego@Sun.COM 	clnt->xa_init = ndr_xa_init;
928334SJose.Borrego@Sun.COM 	clnt->xa_exchange = ndr_xa_exchange;
938334SJose.Borrego@Sun.COM 	clnt->xa_read = ndr_xa_read;
948334SJose.Borrego@Sun.COM 	clnt->xa_preserve = ndr_xa_preserve;
958334SJose.Borrego@Sun.COM 	clnt->xa_destruct = ndr_xa_destruct;
968334SJose.Borrego@Sun.COM 	clnt->xa_release = ndr_xa_release;
975331Samw 
988334SJose.Borrego@Sun.COM 	(void) smbrdr_session_info(fid, &si);
998334SJose.Borrego@Sun.COM 	bzero(&handle->handle, sizeof (ndr_hdid_t));
1008334SJose.Borrego@Sun.COM 	handle->clnt = clnt;
1018334SJose.Borrego@Sun.COM 	handle->remote_os = si.si_server_os;
1025331Samw 
1038334SJose.Borrego@Sun.COM 	if (ndr_rpc_get_heap(handle) == NULL) {
1048334SJose.Borrego@Sun.COM 		free(clnt);
1055331Samw 		return (-1);
1068334SJose.Borrego@Sun.COM 	}
1078334SJose.Borrego@Sun.COM 
1088334SJose.Borrego@Sun.COM 	rc = ndr_clnt_bind(clnt, service, &clnt->binding);
1098334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
1108334SJose.Borrego@Sun.COM 		(void) smbrdr_close_pipe(fid);
1118334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
1128334SJose.Borrego@Sun.COM 		free(clnt);
1138334SJose.Borrego@Sun.COM 		handle->clnt = NULL;
1148334SJose.Borrego@Sun.COM 		return (-1);
1158334SJose.Borrego@Sun.COM 	}
1165331Samw 
1175331Samw 	return (0);
1185331Samw }
1195331Samw 
1205331Samw /*
1218334SJose.Borrego@Sun.COM  * Unbind and close the pipe to an RPC service.
1228334SJose.Borrego@Sun.COM  *
1238334SJose.Borrego@Sun.COM  * If the heap has been preserved we need to go through an xa release.
1248334SJose.Borrego@Sun.COM  * The heap is preserved during an RPC call because that's where data
1258334SJose.Borrego@Sun.COM  * returned from the server is stored.
1265331Samw  *
1278334SJose.Borrego@Sun.COM  * Otherwise we destroy the heap directly.
1288334SJose.Borrego@Sun.COM  */
1298334SJose.Borrego@Sun.COM void
1308334SJose.Borrego@Sun.COM ndr_rpc_unbind(mlsvc_handle_t *handle)
1318334SJose.Borrego@Sun.COM {
1328334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
1338334SJose.Borrego@Sun.COM 
1348334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved)
1358334SJose.Borrego@Sun.COM 		ndr_clnt_free_heap(clnt);
1368334SJose.Borrego@Sun.COM 	else
1378334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
1388334SJose.Borrego@Sun.COM 
1398334SJose.Borrego@Sun.COM 	(void) smbrdr_close_pipe(clnt->fid);
1408334SJose.Borrego@Sun.COM 	free(handle->clnt);
1418334SJose.Borrego@Sun.COM 	bzero(handle, sizeof (mlsvc_handle_t));
1428334SJose.Borrego@Sun.COM }
1438334SJose.Borrego@Sun.COM 
1448334SJose.Borrego@Sun.COM /*
1458334SJose.Borrego@Sun.COM  * Call the RPC function identified by opnum.  The remote service is
1468334SJose.Borrego@Sun.COM  * identified by the handle, which should have been initialized by
1478334SJose.Borrego@Sun.COM  * ndr_rpc_bind.
1488334SJose.Borrego@Sun.COM  *
1498334SJose.Borrego@Sun.COM  * If the RPC call is successful (returns 0), the caller must call
1508334SJose.Borrego@Sun.COM  * ndr_rpc_release to release the heap.  Otherwise, we release the
1518334SJose.Borrego@Sun.COM  * heap here.
1525331Samw  */
1535331Samw int
1548334SJose.Borrego@Sun.COM ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
1558334SJose.Borrego@Sun.COM {
1568334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
1578334SJose.Borrego@Sun.COM 	int rc;
1588334SJose.Borrego@Sun.COM 
1598334SJose.Borrego@Sun.COM 	if (ndr_rpc_get_heap(handle) == NULL)
1608334SJose.Borrego@Sun.COM 		return (-1);
1618334SJose.Borrego@Sun.COM 
1628334SJose.Borrego@Sun.COM 	rc = ndr_clnt_call(clnt->binding, opnum, params);
1638334SJose.Borrego@Sun.COM 
1648334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
1658334SJose.Borrego@Sun.COM 		ndr_rpc_release(handle);
1668334SJose.Borrego@Sun.COM 		return (-1);
1678334SJose.Borrego@Sun.COM 	}
1688334SJose.Borrego@Sun.COM 
1698334SJose.Borrego@Sun.COM 	return (0);
1708334SJose.Borrego@Sun.COM }
1718334SJose.Borrego@Sun.COM 
1728334SJose.Borrego@Sun.COM /*
17310122SJordan.Brown@Sun.COM  * Set information about the remote RPC server in the handle.
17410122SJordan.Brown@Sun.COM  */
17510122SJordan.Brown@Sun.COM void
17610122SJordan.Brown@Sun.COM ndr_rpc_server_setinfo(mlsvc_handle_t *handle,
17710122SJordan.Brown@Sun.COM     const srvsvc_server_info_t *svinfo)
17810122SJordan.Brown@Sun.COM {
17910122SJordan.Brown@Sun.COM 	bcopy(svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
18010122SJordan.Brown@Sun.COM 	handle->svinfo.sv_name = NULL;
18110122SJordan.Brown@Sun.COM 	handle->svinfo.sv_comment = NULL;
18210122SJordan.Brown@Sun.COM 
18310122SJordan.Brown@Sun.COM 	if (svinfo->sv_version_major > 4)
18410122SJordan.Brown@Sun.COM 		handle->remote_os = NATIVE_OS_WIN2000;
18510122SJordan.Brown@Sun.COM 	else
18610122SJordan.Brown@Sun.COM 		handle->remote_os = NATIVE_OS_WINNT;
18710122SJordan.Brown@Sun.COM 
18810122SJordan.Brown@Sun.COM 	smb_tracef("NdrRpcServerSetInfo: %s (version %d.%d)",
18910122SJordan.Brown@Sun.COM 	    svinfo->sv_name ? svinfo->sv_name : "<unknown>",
19010122SJordan.Brown@Sun.COM 	    svinfo->sv_version_major, svinfo->sv_version_minor);
19110122SJordan.Brown@Sun.COM }
19210122SJordan.Brown@Sun.COM 
19310122SJordan.Brown@Sun.COM /*
19410122SJordan.Brown@Sun.COM  * Get information about the remote RPC server from the handle.
19510122SJordan.Brown@Sun.COM  */
19610122SJordan.Brown@Sun.COM void
19710122SJordan.Brown@Sun.COM ndr_rpc_server_getinfo(mlsvc_handle_t *handle, srvsvc_server_info_t *svinfo)
19810122SJordan.Brown@Sun.COM {
19910122SJordan.Brown@Sun.COM 	bcopy(&handle->svinfo, svinfo, sizeof (srvsvc_server_info_t));
20010122SJordan.Brown@Sun.COM }
20110122SJordan.Brown@Sun.COM 
20210122SJordan.Brown@Sun.COM /*
2038334SJose.Borrego@Sun.COM  * Returns the Native-OS of the RPC server.
2048334SJose.Borrego@Sun.COM  */
2058334SJose.Borrego@Sun.COM int
2068334SJose.Borrego@Sun.COM ndr_rpc_server_os(mlsvc_handle_t *handle)
2075331Samw {
2088334SJose.Borrego@Sun.COM 	return (handle->remote_os);
2098334SJose.Borrego@Sun.COM }
2108334SJose.Borrego@Sun.COM 
211*10504SKeyur.Desai@Sun.COM /*
212*10504SKeyur.Desai@Sun.COM  * Get the session key from a bound RPC client handle.
213*10504SKeyur.Desai@Sun.COM  *
214*10504SKeyur.Desai@Sun.COM  * The key returned is the 16-byte "user session key"
215*10504SKeyur.Desai@Sun.COM  * established by the underlying authentication protocol
216*10504SKeyur.Desai@Sun.COM  * (either Kerberos or NTLM).  This key is needed for
217*10504SKeyur.Desai@Sun.COM  * SAM RPC calls such as SamrSetInformationUser, etc.
218*10504SKeyur.Desai@Sun.COM  * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
219*10504SKeyur.Desai@Sun.COM  *
220*10504SKeyur.Desai@Sun.COM  * Returns zero (success) or an errno.
221*10504SKeyur.Desai@Sun.COM  */
222*10504SKeyur.Desai@Sun.COM int
223*10504SKeyur.Desai@Sun.COM ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
224*10504SKeyur.Desai@Sun.COM 	unsigned char *ssn_key, size_t len)
225*10504SKeyur.Desai@Sun.COM {
226*10504SKeyur.Desai@Sun.COM 	ndr_client_t *clnt = handle->clnt;
227*10504SKeyur.Desai@Sun.COM 	int rc;
228*10504SKeyur.Desai@Sun.COM 
229*10504SKeyur.Desai@Sun.COM 	if (clnt == NULL)
230*10504SKeyur.Desai@Sun.COM 		return (EINVAL);
231*10504SKeyur.Desai@Sun.COM 
232*10504SKeyur.Desai@Sun.COM 	rc = smbrdr_get_ssnkey(clnt->fid, ssn_key, len);
233*10504SKeyur.Desai@Sun.COM 	return (rc);
234*10504SKeyur.Desai@Sun.COM }
235*10504SKeyur.Desai@Sun.COM 
2368334SJose.Borrego@Sun.COM void *
2378334SJose.Borrego@Sun.COM ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
2388334SJose.Borrego@Sun.COM {
2398334SJose.Borrego@Sun.COM 	ndr_heap_t *heap;
2408334SJose.Borrego@Sun.COM 
2418334SJose.Borrego@Sun.COM 	if ((heap = ndr_rpc_get_heap(handle)) == NULL)
2428334SJose.Borrego@Sun.COM 		return (NULL);
2438334SJose.Borrego@Sun.COM 
2448334SJose.Borrego@Sun.COM 	return (ndr_heap_malloc(heap, size));
2458334SJose.Borrego@Sun.COM }
2468334SJose.Borrego@Sun.COM 
2478334SJose.Borrego@Sun.COM ndr_heap_t *
2488334SJose.Borrego@Sun.COM ndr_rpc_get_heap(mlsvc_handle_t *handle)
2498334SJose.Borrego@Sun.COM {
2508334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
2518334SJose.Borrego@Sun.COM 
2528334SJose.Borrego@Sun.COM 	if (clnt->heap == NULL)
2538334SJose.Borrego@Sun.COM 		clnt->heap = ndr_heap_create();
2548334SJose.Borrego@Sun.COM 
2558334SJose.Borrego@Sun.COM 	return (clnt->heap);
2565331Samw }
2575331Samw 
2585331Samw /*
2598334SJose.Borrego@Sun.COM  * Must be called by RPC clients to free the heap after a successful RPC
2608334SJose.Borrego@Sun.COM  * call, i.e. ndr_rpc_call returned 0.  The caller should take a copy
2618334SJose.Borrego@Sun.COM  * of any data returned by the RPC prior to calling this function because
2628334SJose.Borrego@Sun.COM  * returned data is in the heap.
2635331Samw  */
2645331Samw void
2658334SJose.Borrego@Sun.COM ndr_rpc_release(mlsvc_handle_t *handle)
2668334SJose.Borrego@Sun.COM {
2678334SJose.Borrego@Sun.COM 	ndr_client_t *clnt = handle->clnt;
2688334SJose.Borrego@Sun.COM 
2698334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved)
2708334SJose.Borrego@Sun.COM 		ndr_clnt_free_heap(clnt);
2718334SJose.Borrego@Sun.COM 	else
2728334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
2738334SJose.Borrego@Sun.COM 
2748334SJose.Borrego@Sun.COM 	clnt->heap = NULL;
2758334SJose.Borrego@Sun.COM }
2768334SJose.Borrego@Sun.COM 
2778334SJose.Borrego@Sun.COM /*
2788334SJose.Borrego@Sun.COM  * Returns true if the handle is null.
2798334SJose.Borrego@Sun.COM  * Otherwise returns false.
2808334SJose.Borrego@Sun.COM  */
2818334SJose.Borrego@Sun.COM boolean_t
2828334SJose.Borrego@Sun.COM ndr_is_null_handle(mlsvc_handle_t *handle)
2835331Samw {
2848334SJose.Borrego@Sun.COM 	static ndr_hdid_t zero_handle;
2858334SJose.Borrego@Sun.COM 
2868334SJose.Borrego@Sun.COM 	if (handle == NULL || handle->clnt == NULL)
2878334SJose.Borrego@Sun.COM 		return (B_TRUE);
2888334SJose.Borrego@Sun.COM 
2898334SJose.Borrego@Sun.COM 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
2908334SJose.Borrego@Sun.COM 		return (B_TRUE);
2918334SJose.Borrego@Sun.COM 
2928334SJose.Borrego@Sun.COM 	return (B_FALSE);
2938334SJose.Borrego@Sun.COM }
2948334SJose.Borrego@Sun.COM 
2958334SJose.Borrego@Sun.COM /*
2968334SJose.Borrego@Sun.COM  * Returns true if the handle is the top level bind handle.
2978334SJose.Borrego@Sun.COM  * Otherwise returns false.
2988334SJose.Borrego@Sun.COM  */
2998334SJose.Borrego@Sun.COM boolean_t
3008334SJose.Borrego@Sun.COM ndr_is_bind_handle(mlsvc_handle_t *handle)
3018334SJose.Borrego@Sun.COM {
3028334SJose.Borrego@Sun.COM 	return (handle->clnt->handle == &handle->handle);
3035331Samw }
3045331Samw 
3055331Samw /*
3068334SJose.Borrego@Sun.COM  * Pass the client reference from parent to child.
3075331Samw  */
3088334SJose.Borrego@Sun.COM void
3098334SJose.Borrego@Sun.COM ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
3108334SJose.Borrego@Sun.COM {
3118334SJose.Borrego@Sun.COM 	child->clnt = parent->clnt;
3128334SJose.Borrego@Sun.COM 	child->remote_os = parent->remote_os;
3138334SJose.Borrego@Sun.COM }
3148334SJose.Borrego@Sun.COM 
3158334SJose.Borrego@Sun.COM void
3168334SJose.Borrego@Sun.COM ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
3175331Samw {
3188334SJose.Borrego@Sun.COM 	ndr_service_t *svc;
3198334SJose.Borrego@Sun.COM 	char *name = "NDR RPC";
3208334SJose.Borrego@Sun.COM 	char *s = "unknown";
3218334SJose.Borrego@Sun.COM 
3228334SJose.Borrego@Sun.COM 	if (status == 0)
3238334SJose.Borrego@Sun.COM 		s = "success";
3248334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_ERROR(status))
3258334SJose.Borrego@Sun.COM 		s = "error";
3268334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_WARNING(status))
3278334SJose.Borrego@Sun.COM 		s = "warning";
3288334SJose.Borrego@Sun.COM 	else if (NT_SC_IS_INFO(status))
3298334SJose.Borrego@Sun.COM 		s = "info";
3308334SJose.Borrego@Sun.COM 
3318334SJose.Borrego@Sun.COM 	if (handle) {
3328334SJose.Borrego@Sun.COM 		svc = handle->clnt->binding->service;
3338334SJose.Borrego@Sun.COM 		name = svc->name;
3348334SJose.Borrego@Sun.COM 	}
3355331Samw 
3368334SJose.Borrego@Sun.COM 	smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
3378334SJose.Borrego@Sun.COM 	    name, opnum, s, xlate_nt_status(status), status);
3388334SJose.Borrego@Sun.COM }
3398334SJose.Borrego@Sun.COM 
3408334SJose.Borrego@Sun.COM /*
3418334SJose.Borrego@Sun.COM  * The following functions provide the client callback interface.
3428334SJose.Borrego@Sun.COM  * If the caller hasn't provided a heap, create one here.
3438334SJose.Borrego@Sun.COM  */
3448334SJose.Borrego@Sun.COM static int
3458334SJose.Borrego@Sun.COM ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
3468334SJose.Borrego@Sun.COM {
3478334SJose.Borrego@Sun.COM 	ndr_stream_t *recv_nds = &mxa->recv_nds;
3488334SJose.Borrego@Sun.COM 	ndr_stream_t *send_nds = &mxa->send_nds;
3498334SJose.Borrego@Sun.COM 	ndr_heap_t *heap = clnt->heap;
3508334SJose.Borrego@Sun.COM 
3518334SJose.Borrego@Sun.COM 	if (heap == NULL) {
3528334SJose.Borrego@Sun.COM 		if ((heap = ndr_heap_create()) == NULL)
3535331Samw 			return (-1);
3548334SJose.Borrego@Sun.COM 
3558334SJose.Borrego@Sun.COM 		clnt->heap = heap;
3565331Samw 	}
3575331Samw 
3585331Samw 	mxa->heap = heap;
3595331Samw 
3608334SJose.Borrego@Sun.COM 	nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
3619914Samw@Sun.COM 	nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
3629914Samw@Sun.COM 	    NDR_MODE_RETURN_RECV, heap);
3635331Samw 	return (0);
3645331Samw }
3655331Samw 
3665331Samw /*
3675331Samw  * This is the entry pointy for an RPC client call exchange with
3685331Samw  * a server, which will result in an smbrdr SmbTransact request.
3695331Samw  *
3705331Samw  * SmbTransact should return the number of bytes received, which
3715331Samw  * we record as the PDU size, or a negative error code.
3725331Samw  */
3735331Samw static int
3748334SJose.Borrego@Sun.COM ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
3755331Samw {
3768334SJose.Borrego@Sun.COM 	ndr_stream_t *recv_nds = &mxa->recv_nds;
3778334SJose.Borrego@Sun.COM 	ndr_stream_t *send_nds = &mxa->send_nds;
3788334SJose.Borrego@Sun.COM 	int nbytes;
3795331Samw 
3808334SJose.Borrego@Sun.COM 	nbytes = smbrdr_transact(clnt->fid,
3818334SJose.Borrego@Sun.COM 	    (char *)send_nds->pdu_base_offset, send_nds->pdu_size,
3828334SJose.Borrego@Sun.COM 	    (char *)recv_nds->pdu_base_offset, recv_nds->pdu_max_size);
3835331Samw 
3848334SJose.Borrego@Sun.COM 	if (nbytes < 0) {
3858334SJose.Borrego@Sun.COM 		recv_nds->pdu_size = 0;
3868334SJose.Borrego@Sun.COM 		return (-1);
3878334SJose.Borrego@Sun.COM 	}
3885331Samw 
3898334SJose.Borrego@Sun.COM 	recv_nds->pdu_size = nbytes;
3908334SJose.Borrego@Sun.COM 	return (nbytes);
3915331Samw }
3925331Samw 
3935331Samw /*
3945331Samw  * This entry point will be invoked if the xa-exchange response contained
3955331Samw  * only the first fragment of a multi-fragment response.  The RPC client
3965331Samw  * code will then make repeated xa-read requests to obtain the remaining
3975331Samw  * fragments, which will result in smbrdr SmbReadX requests.
3985331Samw  *
3995331Samw  * SmbReadX should return the number of bytes received, in which case we
4005331Samw  * expand the PDU size to include the received data, or a negative error
4015331Samw  * code.
4025331Samw  */
4035331Samw static int
4048334SJose.Borrego@Sun.COM ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
4055331Samw {
4068334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->recv_nds;
4075331Samw 	int len;
4088334SJose.Borrego@Sun.COM 	int nbytes;
4095331Samw 
4108334SJose.Borrego@Sun.COM 	if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
4115331Samw 		return (-1);
4125331Samw 
4138334SJose.Borrego@Sun.COM 	nbytes = smbrdr_readx(clnt->fid,
4148334SJose.Borrego@Sun.COM 	    (char *)nds->pdu_base_offset + nds->pdu_size, len);
4155331Samw 
4168334SJose.Borrego@Sun.COM 	if (nbytes < 0)
4175331Samw 		return (-1);
4185331Samw 
4198334SJose.Borrego@Sun.COM 	nds->pdu_size += nbytes;
4205331Samw 
4218334SJose.Borrego@Sun.COM 	if (nds->pdu_size > nds->pdu_max_size) {
4228334SJose.Borrego@Sun.COM 		nds->pdu_size = nds->pdu_max_size;
4235331Samw 		return (-1);
4245331Samw 	}
4255331Samw 
4268334SJose.Borrego@Sun.COM 	return (nbytes);
4275331Samw }
4285331Samw 
4295331Samw /*
4308334SJose.Borrego@Sun.COM  * Preserve the heap so that the client application has access to data
4318334SJose.Borrego@Sun.COM  * returned from the server after an RPC call.
4325331Samw  */
4338334SJose.Borrego@Sun.COM static void
4348334SJose.Borrego@Sun.COM ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
4355331Samw {
4368334SJose.Borrego@Sun.COM 	assert(clnt->heap == mxa->heap);
4375331Samw 
4388334SJose.Borrego@Sun.COM 	clnt->heap_preserved = B_TRUE;
4395331Samw 	mxa->heap = NULL;
4405331Samw }
4415331Samw 
4425331Samw /*
4438334SJose.Borrego@Sun.COM  * Dispose of the transaction streams.  If the heap has not been
4448334SJose.Borrego@Sun.COM  * preserved, we can destroy it here.
4455331Samw  */
4468334SJose.Borrego@Sun.COM static void
4478334SJose.Borrego@Sun.COM ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
4485331Samw {
4498334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->recv_nds);
4508334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->send_nds);
4518334SJose.Borrego@Sun.COM 
4528334SJose.Borrego@Sun.COM 	if (!clnt->heap_preserved) {
4538334SJose.Borrego@Sun.COM 		ndr_heap_destroy(mxa->heap);
4548334SJose.Borrego@Sun.COM 		mxa->heap = NULL;
4558334SJose.Borrego@Sun.COM 		clnt->heap = NULL;
4565331Samw 	}
4575331Samw }
4585331Samw 
4595331Samw /*
4608334SJose.Borrego@Sun.COM  * Dispose of a preserved heap.
4615331Samw  */
4625331Samw static void
4638334SJose.Borrego@Sun.COM ndr_xa_release(ndr_client_t *clnt)
4645331Samw {
4658334SJose.Borrego@Sun.COM 	if (clnt->heap_preserved) {
4668334SJose.Borrego@Sun.COM 		ndr_heap_destroy(clnt->heap);
4678334SJose.Borrego@Sun.COM 		clnt->heap = NULL;
4688334SJose.Borrego@Sun.COM 		clnt->heap_preserved = B_FALSE;
4695331Samw 	}
4705331Samw }
471