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