1dc20a302Sas200622 /* 2dc20a302Sas200622 * CDDL HEADER START 3dc20a302Sas200622 * 4dc20a302Sas200622 * The contents of this file are subject to the terms of the 5dc20a302Sas200622 * Common Development and Distribution License (the "License"). 6dc20a302Sas200622 * You may not use this file except in compliance with the License. 7dc20a302Sas200622 * 8dc20a302Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9dc20a302Sas200622 * or http://www.opensolaris.org/os/licensing. 10dc20a302Sas200622 * See the License for the specific language governing permissions 11dc20a302Sas200622 * and limitations under the License. 12dc20a302Sas200622 * 13dc20a302Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14dc20a302Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15dc20a302Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16dc20a302Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17dc20a302Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18dc20a302Sas200622 * 19dc20a302Sas200622 * CDDL HEADER END 20dc20a302Sas200622 */ 21dc20a302Sas200622 /* 22*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23dc20a302Sas200622 * Use is subject to license terms. 24dc20a302Sas200622 */ 25dc20a302Sas200622 26dc20a302Sas200622 #include <sys/errno.h> 27dc20a302Sas200622 #include <string.h> 28dc20a302Sas200622 #include <strings.h> 29dc20a302Sas200622 30dc20a302Sas200622 #include <smbsrv/libsmb.h> 318d7e4166Sjose borrego #include <smbsrv/libmlrpc.h> 32dc20a302Sas200622 338d7e4166Sjose borrego #define NDR_DEFAULT_FRAGSZ 8192 340658b32dSAlan Wright #define NDR_MULTI_FRAGSZ (60 * 1024) 35dc20a302Sas200622 368d7e4166Sjose borrego static void ndr_clnt_init_hdr(ndr_client_t *, ndr_xa_t *); 378d7e4166Sjose borrego static int ndr_clnt_get_frags(ndr_client_t *, ndr_xa_t *); 380658b32dSAlan Wright static int ndr_clnt_get_frag(ndr_client_t *, ndr_xa_t *, ndr_common_header_t *); 39dc20a302Sas200622 40dc20a302Sas200622 int 418d7e4166Sjose borrego ndr_clnt_bind(ndr_client_t *clnt, const char *service_name, 428d7e4166Sjose borrego ndr_binding_t **ret_binding_p) 43dc20a302Sas200622 { 448d7e4166Sjose borrego ndr_service_t *msvc; 458d7e4166Sjose borrego ndr_binding_t *mbind; 468d7e4166Sjose borrego ndr_xa_t mxa; 472c1b14e5Sjose borrego ndr_bind_hdr_t *bhdr; 488d7e4166Sjose borrego ndr_p_cont_elem_t *pce; 492c1b14e5Sjose borrego ndr_bind_ack_hdr_t *bahdr; 508d7e4166Sjose borrego ndr_p_result_t *pre; 51dc20a302Sas200622 int rc; 52dc20a302Sas200622 53dc20a302Sas200622 bzero(&mxa, sizeof (mxa)); 54dc20a302Sas200622 558d7e4166Sjose borrego msvc = ndr_svc_lookup_name(service_name); 56dc20a302Sas200622 if (msvc == NULL) 578d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID); 58dc20a302Sas200622 598d7e4166Sjose borrego mxa.binding_list = clnt->binding_list; 608d7e4166Sjose borrego if ((mbind = ndr_svc_new_binding(&mxa)) == NULL) 618d7e4166Sjose borrego return (NDR_DRC_FAULT_API_BIND_NO_SLOTS); 62dc20a302Sas200622 638d7e4166Sjose borrego ndr_clnt_init_hdr(clnt, &mxa); 64dc20a302Sas200622 65dc20a302Sas200622 bhdr = &mxa.send_hdr.bind_hdr; 668d7e4166Sjose borrego bhdr->common_hdr.ptype = NDR_PTYPE_BIND; 67dc20a302Sas200622 bhdr->common_hdr.frag_length = sizeof (*bhdr); 688d7e4166Sjose borrego bhdr->max_xmit_frag = NDR_DEFAULT_FRAGSZ; 698d7e4166Sjose borrego bhdr->max_recv_frag = NDR_DEFAULT_FRAGSZ; 70dc20a302Sas200622 bhdr->assoc_group_id = 0; 71dc20a302Sas200622 bhdr->p_context_elem.n_context_elem = 1; 72dc20a302Sas200622 73dc20a302Sas200622 /* Assign presentation context id */ 74dc20a302Sas200622 pce = &bhdr->p_context_elem.p_cont_elem[0]; 758d7e4166Sjose borrego pce->p_cont_id = clnt->next_p_cont_id++; 76dc20a302Sas200622 pce->n_transfer_syn = 1; 77dc20a302Sas200622 78dc20a302Sas200622 /* Set up UUIDs and versions from the service */ 79dc20a302Sas200622 pce->abstract_syntax.if_version = msvc->abstract_syntax_version; 808d7e4166Sjose borrego rc = ndr_uuid_parse(msvc->abstract_syntax_uuid, 81dc20a302Sas200622 &pce->abstract_syntax.if_uuid); 828d7e4166Sjose borrego if (rc != 0) 838d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID); 84dc20a302Sas200622 85dc20a302Sas200622 pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version; 868d7e4166Sjose borrego rc = ndr_uuid_parse(msvc->transfer_syntax_uuid, 87dc20a302Sas200622 &pce->transfer_syntaxes[0].if_uuid); 888d7e4166Sjose borrego if (rc != 0) 898d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID); 90dc20a302Sas200622 91dc20a302Sas200622 /* Format and exchange the PDU */ 92dc20a302Sas200622 938d7e4166Sjose borrego if ((*clnt->xa_init)(clnt, &mxa) < 0) 948d7e4166Sjose borrego return (NDR_DRC_FAULT_OUT_OF_MEMORY); 95dc20a302Sas200622 968d7e4166Sjose borrego rc = ndr_encode_pdu_hdr(&mxa); 978d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 98dc20a302Sas200622 goto fault_exit; 99dc20a302Sas200622 1008d7e4166Sjose borrego if ((*clnt->xa_exchange)(clnt, &mxa) < 0) { 1018d7e4166Sjose borrego rc = NDR_DRC_FAULT_SEND_FAILED; 102dc20a302Sas200622 goto fault_exit; 1038d7e4166Sjose borrego } 104dc20a302Sas200622 1058d7e4166Sjose borrego rc = ndr_decode_pdu_hdr(&mxa); 1068d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 107dc20a302Sas200622 goto fault_exit; 108dc20a302Sas200622 109dc20a302Sas200622 /* done with buffers */ 1108d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa); 111dc20a302Sas200622 112dc20a302Sas200622 bahdr = &mxa.recv_hdr.bind_ack_hdr; 113dc20a302Sas200622 1148d7e4166Sjose borrego if (mxa.ptype != NDR_PTYPE_BIND_ACK) 1158d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED); 116dc20a302Sas200622 117dc20a302Sas200622 if (bahdr->p_result_list.n_results != 1) 1188d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED); 119dc20a302Sas200622 120dc20a302Sas200622 pre = &bahdr->p_result_list.p_results[0]; 121dc20a302Sas200622 1228d7e4166Sjose borrego if (pre->result != NDR_PCDR_ACCEPTANCE) 1238d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED); 124dc20a302Sas200622 125dc20a302Sas200622 mbind->p_cont_id = pce->p_cont_id; 1268d7e4166Sjose borrego mbind->which_side = NDR_BIND_SIDE_CLIENT; 1278d7e4166Sjose borrego mbind->clnt = clnt; 128dc20a302Sas200622 mbind->service = msvc; 129dc20a302Sas200622 mbind->instance_specific = 0; 130dc20a302Sas200622 131dc20a302Sas200622 *ret_binding_p = mbind; 1328d7e4166Sjose borrego return (NDR_DRC_OK); 133dc20a302Sas200622 134dc20a302Sas200622 fault_exit: 1358d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa); 136dc20a302Sas200622 return (rc); 137dc20a302Sas200622 } 138dc20a302Sas200622 139dc20a302Sas200622 int 1408d7e4166Sjose borrego ndr_clnt_call(ndr_binding_t *mbind, int opnum, void *params) 141dc20a302Sas200622 { 1428d7e4166Sjose borrego ndr_client_t *clnt = mbind->clnt; 1438d7e4166Sjose borrego ndr_service_t *msvc = mbind->service; 1448d7e4166Sjose borrego ndr_xa_t mxa; 1452c1b14e5Sjose borrego ndr_request_hdr_t *reqhdr; 1462c1b14e5Sjose borrego ndr_common_header_t *rsphdr; 147dc20a302Sas200622 unsigned long recv_pdu_scan_offset; 148dc20a302Sas200622 int rc; 149dc20a302Sas200622 150b1352070SAlan Wright if (ndr_svc_lookup_name(msvc->name) == NULL) 151b1352070SAlan Wright return (NDR_DRC_FAULT_API_SERVICE_INVALID); 152dc20a302Sas200622 153dc20a302Sas200622 bzero(&mxa, sizeof (mxa)); 1548d7e4166Sjose borrego mxa.ptype = NDR_PTYPE_REQUEST; 155dc20a302Sas200622 mxa.opnum = opnum; 156dc20a302Sas200622 mxa.binding = mbind; 157dc20a302Sas200622 1588d7e4166Sjose borrego ndr_clnt_init_hdr(clnt, &mxa); 159dc20a302Sas200622 160dc20a302Sas200622 reqhdr = &mxa.send_hdr.request_hdr; 1618d7e4166Sjose borrego reqhdr->common_hdr.ptype = NDR_PTYPE_REQUEST; 162dc20a302Sas200622 reqhdr->p_cont_id = mbind->p_cont_id; 163dc20a302Sas200622 reqhdr->opnum = opnum; 164dc20a302Sas200622 1658d7e4166Sjose borrego rc = (*clnt->xa_init)(clnt, &mxa); 1668d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 167dc20a302Sas200622 return (rc); 168dc20a302Sas200622 169dc20a302Sas200622 /* Reserve room for hdr */ 1708d7e4166Sjose borrego mxa.send_nds.pdu_scan_offset = sizeof (*reqhdr); 171dc20a302Sas200622 1728d7e4166Sjose borrego rc = ndr_encode_call(&mxa, params); 1738d7e4166Sjose borrego if (!NDR_DRC_IS_OK(rc)) 174dc20a302Sas200622 goto fault_exit; 175dc20a302Sas200622 1768d7e4166Sjose borrego mxa.send_nds.pdu_scan_offset = 0; 177dc20a302Sas200622 178dc20a302Sas200622 /* 179dc20a302Sas200622 * Now we have the PDU size, we need to set up the 180dc20a302Sas200622 * frag_length and calculate the alloc_hint. 181dc20a302Sas200622 */ 1828d7e4166Sjose borrego mxa.send_hdr.common_hdr.frag_length = mxa.send_nds.pdu_size; 1838d7e4166Sjose borrego reqhdr->alloc_hint = mxa.send_nds.pdu_size - 1842c1b14e5Sjose borrego sizeof (ndr_request_hdr_t); 185dc20a302Sas200622 1868d7e4166Sjose borrego rc = ndr_encode_pdu_hdr(&mxa); 1878d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 188dc20a302Sas200622 goto fault_exit; 189dc20a302Sas200622 1908d7e4166Sjose borrego rc = (*clnt->xa_exchange)(clnt, &mxa); 1918d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 192dc20a302Sas200622 goto fault_exit; 193dc20a302Sas200622 1948d7e4166Sjose borrego rc = ndr_decode_pdu_hdr(&mxa); 1958d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 196dc20a302Sas200622 goto fault_exit; 197dc20a302Sas200622 1988d7e4166Sjose borrego if (mxa.ptype != NDR_PTYPE_RESPONSE) { 1998d7e4166Sjose borrego rc = NDR_DRC_FAULT_RECEIVED_MALFORMED; 200dc20a302Sas200622 goto fault_exit; 201dc20a302Sas200622 } 202dc20a302Sas200622 203dc20a302Sas200622 rsphdr = &mxa.recv_hdr.common_hdr; 204dc20a302Sas200622 2058d7e4166Sjose borrego if (!NDR_IS_LAST_FRAG(rsphdr->pfc_flags)) { 206dc20a302Sas200622 /* 207dc20a302Sas200622 * This is a multi-fragment response. 208dc20a302Sas200622 * Preserve the current scan offset while getting 209dc20a302Sas200622 * fragments so that we can continue afterward 210dc20a302Sas200622 * as if we had received the entire response as 211dc20a302Sas200622 * a single PDU. 212dc20a302Sas200622 */ 2130658b32dSAlan Wright (void) NDS_GROW_PDU(&mxa.recv_nds, NDR_MULTI_FRAGSZ, NULL); 2140658b32dSAlan Wright 2158d7e4166Sjose borrego recv_pdu_scan_offset = mxa.recv_nds.pdu_scan_offset; 2160658b32dSAlan Wright mxa.recv_nds.pdu_scan_offset = rsphdr->frag_length; 2170658b32dSAlan Wright mxa.recv_nds.pdu_size = rsphdr->frag_length; 218dc20a302Sas200622 2198d7e4166Sjose borrego if (ndr_clnt_get_frags(clnt, &mxa) < 0) { 2208d7e4166Sjose borrego rc = NDR_DRC_FAULT_RECEIVED_MALFORMED; 221dc20a302Sas200622 goto fault_exit; 222dc20a302Sas200622 } 223dc20a302Sas200622 2248d7e4166Sjose borrego mxa.recv_nds.pdu_scan_offset = recv_pdu_scan_offset; 225dc20a302Sas200622 } 226dc20a302Sas200622 2278d7e4166Sjose borrego rc = ndr_decode_return(&mxa, params); 2288d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 229dc20a302Sas200622 goto fault_exit; 230dc20a302Sas200622 2318d7e4166Sjose borrego (*clnt->xa_preserve)(clnt, &mxa); 2328d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa); 2338d7e4166Sjose borrego return (NDR_DRC_OK); 234dc20a302Sas200622 235dc20a302Sas200622 fault_exit: 2368d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa); 237dc20a302Sas200622 return (rc); 238dc20a302Sas200622 } 239dc20a302Sas200622 240dc20a302Sas200622 void 2418d7e4166Sjose borrego ndr_clnt_free_heap(ndr_client_t *clnt) 242dc20a302Sas200622 { 2438d7e4166Sjose borrego (*clnt->xa_release)(clnt); 244dc20a302Sas200622 } 245dc20a302Sas200622 246dc20a302Sas200622 static void 2478d7e4166Sjose borrego ndr_clnt_init_hdr(ndr_client_t *clnt, ndr_xa_t *mxa) 248dc20a302Sas200622 { 2492c1b14e5Sjose borrego ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 250dc20a302Sas200622 251dc20a302Sas200622 hdr->rpc_vers = 5; 252dc20a302Sas200622 hdr->rpc_vers_minor = 0; 2538d7e4166Sjose borrego hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 2548d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII; 255dc20a302Sas200622 #ifndef _BIG_ENDIAN 2568d7e4166Sjose borrego hdr->packed_drep.intg_char_rep |= NDR_REPLAB_INTG_LITTLE_ENDIAN; 257dc20a302Sas200622 #endif 258dc20a302Sas200622 /* hdr->frag_length */ 259dc20a302Sas200622 hdr->auth_length = 0; 2608d7e4166Sjose borrego hdr->call_id = clnt->next_call_id++; 261dc20a302Sas200622 } 262dc20a302Sas200622 263dc20a302Sas200622 /* 2648d7e4166Sjose borrego * ndr_clnt_get_frags 265dc20a302Sas200622 * 266dc20a302Sas200622 * A DCE RPC message that is larger than a single fragment is transmitted 267dc20a302Sas200622 * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for 268dc20a302Sas200622 * both Windows 2000 and 2003. 269dc20a302Sas200622 * 270dc20a302Sas200622 * Collect RPC fragments and append them to the receive stream buffer. 271dc20a302Sas200622 * Each received fragment has a header, which we need to remove as we 2720658b32dSAlan Wright * build the full RPC PDU. The scan offset is used to track frag headers. 273dc20a302Sas200622 */ 274dc20a302Sas200622 static int 2758d7e4166Sjose borrego ndr_clnt_get_frags(ndr_client_t *clnt, ndr_xa_t *mxa) 276dc20a302Sas200622 { 2778d7e4166Sjose borrego ndr_stream_t *nds = &mxa->recv_nds; 2782c1b14e5Sjose borrego ndr_common_header_t hdr; 279dc20a302Sas200622 int frag_size; 280dc20a302Sas200622 int last_frag; 281dc20a302Sas200622 282dc20a302Sas200622 do { 2830658b32dSAlan Wright if (ndr_clnt_get_frag(clnt, mxa, &hdr) < 0) { 2840658b32dSAlan Wright nds_show_state(nds); 285dc20a302Sas200622 return (-1); 286dc20a302Sas200622 } 287dc20a302Sas200622 2880658b32dSAlan Wright last_frag = NDR_IS_LAST_FRAG(hdr.pfc_flags); 2890658b32dSAlan Wright frag_size = hdr.frag_length; 290dc20a302Sas200622 2910658b32dSAlan Wright if (frag_size > (nds->pdu_size - nds->pdu_scan_offset)) { 2920658b32dSAlan Wright nds_show_state(nds); 2930658b32dSAlan Wright return (-1); 2940658b32dSAlan Wright } 2950658b32dSAlan Wright 296*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ndr_remove_frag_hdr(nds); 2970658b32dSAlan Wright nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE; 298dc20a302Sas200622 } while (!last_frag); 299dc20a302Sas200622 300dc20a302Sas200622 return (0); 301dc20a302Sas200622 } 3020658b32dSAlan Wright 3030658b32dSAlan Wright /* 3040658b32dSAlan Wright * Read the next RPC fragment. The xa_read() calls correspond to SmbReadX 3050658b32dSAlan Wright * requests. Note that there is no correspondence between SmbReadX buffering 3060658b32dSAlan Wright * and DCE RPC fragment alignment. 3070658b32dSAlan Wright */ 3080658b32dSAlan Wright static int 3090658b32dSAlan Wright ndr_clnt_get_frag(ndr_client_t *clnt, ndr_xa_t *mxa, ndr_common_header_t *hdr) 3100658b32dSAlan Wright { 3110658b32dSAlan Wright ndr_stream_t *nds = &mxa->recv_nds; 3120658b32dSAlan Wright unsigned long available; 3130658b32dSAlan Wright int nbytes = 0; 3140658b32dSAlan Wright 3150658b32dSAlan Wright available = nds->pdu_size - nds->pdu_scan_offset; 3160658b32dSAlan Wright 3170658b32dSAlan Wright while (available < NDR_RSP_HDR_SIZE) { 3180658b32dSAlan Wright if ((nbytes += (*clnt->xa_read)(clnt, mxa)) <= 0) 3190658b32dSAlan Wright return (-1); 3200658b32dSAlan Wright available += nbytes; 3210658b32dSAlan Wright } 3220658b32dSAlan Wright 3230658b32dSAlan Wright ndr_decode_frag_hdr(nds, hdr); 3240658b32dSAlan Wright ndr_show_hdr(hdr); 3250658b32dSAlan Wright 3260658b32dSAlan Wright while (available < hdr->frag_length) { 3270658b32dSAlan Wright if ((nbytes = (*clnt->xa_read)(clnt, mxa)) <= 0) 3280658b32dSAlan Wright return (-1); 3290658b32dSAlan Wright available += nbytes; 3300658b32dSAlan Wright } 3310658b32dSAlan Wright 3320658b32dSAlan Wright return (nbytes); 3330658b32dSAlan Wright } 334