15772Sas200622 /* 25772Sas200622 * CDDL HEADER START 35772Sas200622 * 45772Sas200622 * The contents of this file are subject to the terms of the 55772Sas200622 * Common Development and Distribution License (the "License"). 65772Sas200622 * You may not use this file except in compliance with the License. 75772Sas200622 * 85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95772Sas200622 * or http://www.opensolaris.org/os/licensing. 105772Sas200622 * See the License for the specific language governing permissions 115772Sas200622 * and limitations under the License. 125772Sas200622 * 135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 185772Sas200622 * 195772Sas200622 * CDDL HEADER END 205772Sas200622 */ 215772Sas200622 /* 22*7619SJose.Borrego@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 #include <sys/errno.h> 275772Sas200622 #include <string.h> 285772Sas200622 #include <strings.h> 295772Sas200622 305772Sas200622 #include <smbsrv/libsmb.h> 315772Sas200622 #include <smbsrv/ndr.h> 325772Sas200622 #include <smbsrv/mlrpc.h> 335772Sas200622 345772Sas200622 #define MLRPC_IS_LAST_FRAG(F) ((F) & MLRPC_PFC_LAST_FRAG) 355772Sas200622 #define MLRPC_DEFAULT_FRAGSZ 8192 365772Sas200622 375772Sas200622 static void mlrpc_c_init_hdr(struct mlrpc_client *, struct mlrpc_xaction *); 385772Sas200622 static int mlrpc_c_get_frags(struct mlrpc_client *, struct mlrpc_xaction *); 395772Sas200622 static void mlrpc_c_remove_hdr(struct mlndr_stream *, int *); 405772Sas200622 415772Sas200622 int 425772Sas200622 mlrpc_c_bind(struct mlrpc_client *mcli, char *service_name, 435772Sas200622 struct mlrpc_binding **ret_binding_p) 445772Sas200622 { 455772Sas200622 struct mlrpc_service *msvc; 465772Sas200622 struct mlrpc_binding *mbind; 475772Sas200622 struct mlrpc_xaction mxa; 48*7619SJose.Borrego@Sun.COM ndr_bind_hdr_t *bhdr; 495772Sas200622 mlrpc_p_cont_elem_t *pce; 50*7619SJose.Borrego@Sun.COM ndr_bind_ack_hdr_t *bahdr; 515772Sas200622 mlrpc_p_result_t *pre; 525772Sas200622 int rc; 535772Sas200622 545772Sas200622 bzero(&mxa, sizeof (mxa)); 555772Sas200622 565772Sas200622 msvc = mlrpc_find_service_by_name(service_name); 575772Sas200622 if (msvc == NULL) 585772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 595772Sas200622 605772Sas200622 mxa.binding_list = mcli->binding_list; 615772Sas200622 if ((mbind = mlrpc_new_binding(&mxa)) == NULL) 625772Sas200622 return (MLRPC_DRC_FAULT_API_BIND_NO_SLOTS); 635772Sas200622 645772Sas200622 mlrpc_c_init_hdr(mcli, &mxa); 655772Sas200622 665772Sas200622 bhdr = &mxa.send_hdr.bind_hdr; 675772Sas200622 bhdr->common_hdr.ptype = MLRPC_PTYPE_BIND; 685772Sas200622 bhdr->common_hdr.frag_length = sizeof (*bhdr); 695772Sas200622 bhdr->max_xmit_frag = MLRPC_DEFAULT_FRAGSZ; 705772Sas200622 bhdr->max_recv_frag = MLRPC_DEFAULT_FRAGSZ; 715772Sas200622 bhdr->assoc_group_id = 0; 725772Sas200622 bhdr->p_context_elem.n_context_elem = 1; 735772Sas200622 745772Sas200622 /* Assign presentation context id */ 755772Sas200622 pce = &bhdr->p_context_elem.p_cont_elem[0]; 765772Sas200622 pce->p_cont_id = mcli->next_p_cont_id++; 775772Sas200622 pce->n_transfer_syn = 1; 785772Sas200622 795772Sas200622 /* Set up UUIDs and versions from the service */ 805772Sas200622 pce->abstract_syntax.if_version = msvc->abstract_syntax_version; 815772Sas200622 rc = mlrpc_str_to_uuid(msvc->abstract_syntax_uuid, 825772Sas200622 &pce->abstract_syntax.if_uuid); 835772Sas200622 if (!rc) 845772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 855772Sas200622 865772Sas200622 pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version; 875772Sas200622 rc = mlrpc_str_to_uuid(msvc->transfer_syntax_uuid, 885772Sas200622 &pce->transfer_syntaxes[0].if_uuid); 895772Sas200622 if (!rc) 905772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 915772Sas200622 925772Sas200622 /* Format and exchange the PDU */ 935772Sas200622 945772Sas200622 rc = (*mcli->xa_init)(mcli, &mxa, 0); 955772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 965772Sas200622 return (rc); 975772Sas200622 985772Sas200622 rc = mlrpc_encode_pdu_hdr(&mxa); 995772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1005772Sas200622 goto fault_exit; 1015772Sas200622 1025772Sas200622 rc = (*mcli->xa_exchange)(mcli, &mxa); 1035772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1045772Sas200622 goto fault_exit; 1055772Sas200622 1065772Sas200622 rc = mlrpc_decode_pdu_hdr(&mxa); 1075772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1085772Sas200622 goto fault_exit; 1095772Sas200622 1105772Sas200622 /* done with buffers */ 1115772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 1125772Sas200622 1135772Sas200622 bahdr = &mxa.recv_hdr.bind_ack_hdr; 1145772Sas200622 1155772Sas200622 if (mxa.ptype != MLRPC_PTYPE_BIND_ACK) 1165772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 1175772Sas200622 1185772Sas200622 if (bahdr->p_result_list.n_results != 1) 1195772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 1205772Sas200622 1215772Sas200622 pre = &bahdr->p_result_list.p_results[0]; 1225772Sas200622 1235772Sas200622 if (pre->result != MLRPC_PCDR_ACCEPTANCE) 1245772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 1255772Sas200622 1265772Sas200622 mbind->p_cont_id = pce->p_cont_id; 1275772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_CLIENT; 1285772Sas200622 mbind->context = mcli; 1295772Sas200622 mbind->service = msvc; 1305772Sas200622 mbind->instance_specific = 0; 1315772Sas200622 1325772Sas200622 *ret_binding_p = mbind; 1335772Sas200622 return (MLRPC_DRC_OK); 1345772Sas200622 1355772Sas200622 fault_exit: 1365772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 1375772Sas200622 return (rc); 1385772Sas200622 } 1395772Sas200622 1405772Sas200622 int 1415772Sas200622 mlrpc_c_call(struct mlrpc_binding *mbind, int opnum, void *params, 1425772Sas200622 mlrpc_heapref_t *heapref) 1435772Sas200622 { 1445772Sas200622 struct mlrpc_client *mcli = mbind->context; 1455772Sas200622 struct mlrpc_service *msvc = mbind->service; 1465772Sas200622 struct mlrpc_xaction mxa; 147*7619SJose.Borrego@Sun.COM ndr_request_hdr_t *reqhdr; 148*7619SJose.Borrego@Sun.COM ndr_common_header_t *rsphdr; 1495772Sas200622 unsigned long recv_pdu_scan_offset; 1505772Sas200622 int rc; 1515772Sas200622 1525772Sas200622 if (mlrpc_find_stub_in_svc(msvc, opnum) == NULL) 1535772Sas200622 return (MLRPC_DRC_FAULT_API_OPNUM_INVALID); 1545772Sas200622 1555772Sas200622 bzero(&mxa, sizeof (mxa)); 1565772Sas200622 mxa.ptype = MLRPC_PTYPE_REQUEST; 1575772Sas200622 mxa.opnum = opnum; 1585772Sas200622 mxa.binding = mbind; 1595772Sas200622 1605772Sas200622 mlrpc_c_init_hdr(mcli, &mxa); 1615772Sas200622 1625772Sas200622 reqhdr = &mxa.send_hdr.request_hdr; 1635772Sas200622 reqhdr->common_hdr.ptype = MLRPC_PTYPE_REQUEST; 1645772Sas200622 reqhdr->p_cont_id = mbind->p_cont_id; 1655772Sas200622 reqhdr->opnum = opnum; 1665772Sas200622 1675772Sas200622 rc = (*mcli->xa_init)(mcli, &mxa, heapref->heap); 1685772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1695772Sas200622 return (rc); 1705772Sas200622 1715772Sas200622 /* Reserve room for hdr */ 1725772Sas200622 mxa.send_mlnds.pdu_scan_offset = sizeof (*reqhdr); 1735772Sas200622 1745772Sas200622 rc = mlrpc_encode_call(&mxa, params); 1755772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 1765772Sas200622 goto fault_exit; 1775772Sas200622 1785772Sas200622 mxa.send_mlnds.pdu_scan_offset = 0; 1795772Sas200622 1805772Sas200622 /* 1815772Sas200622 * Now we have the PDU size, we need to set up the 1825772Sas200622 * frag_length and calculate the alloc_hint. 1835772Sas200622 */ 1845772Sas200622 mxa.send_hdr.common_hdr.frag_length = mxa.send_mlnds.pdu_size; 1855772Sas200622 reqhdr->alloc_hint = mxa.send_mlnds.pdu_size - 186*7619SJose.Borrego@Sun.COM sizeof (ndr_request_hdr_t); 1875772Sas200622 1885772Sas200622 rc = mlrpc_encode_pdu_hdr(&mxa); 1895772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1905772Sas200622 goto fault_exit; 1915772Sas200622 1925772Sas200622 rc = (*mcli->xa_exchange)(mcli, &mxa); 1935772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1945772Sas200622 goto fault_exit; 1955772Sas200622 1965772Sas200622 rc = mlrpc_decode_pdu_hdr(&mxa); 1975772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 1985772Sas200622 goto fault_exit; 1995772Sas200622 2005772Sas200622 if (mxa.ptype != MLRPC_PTYPE_RESPONSE) { 2015772Sas200622 rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED; 2025772Sas200622 goto fault_exit; 2035772Sas200622 } 2045772Sas200622 2055772Sas200622 rsphdr = &mxa.recv_hdr.common_hdr; 2065772Sas200622 2075772Sas200622 if (!MLRPC_IS_LAST_FRAG(rsphdr->pfc_flags)) { 2085772Sas200622 /* 2095772Sas200622 * This is a multi-fragment response. 2105772Sas200622 * Preserve the current scan offset while getting 2115772Sas200622 * fragments so that we can continue afterward 2125772Sas200622 * as if we had received the entire response as 2135772Sas200622 * a single PDU. 2145772Sas200622 */ 2155772Sas200622 recv_pdu_scan_offset = mxa.recv_mlnds.pdu_scan_offset; 2165772Sas200622 2175772Sas200622 if (mlrpc_c_get_frags(mcli, &mxa) < 0) { 2185772Sas200622 rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED; 2195772Sas200622 goto fault_exit; 2205772Sas200622 } 2215772Sas200622 2225772Sas200622 mxa.recv_mlnds.pdu_scan_offset = recv_pdu_scan_offset; 2235772Sas200622 } 2245772Sas200622 2255772Sas200622 rc = mlrpc_decode_return(&mxa, params); 2265772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 2275772Sas200622 goto fault_exit; 2285772Sas200622 2295772Sas200622 rc = (*mcli->xa_preserve)(mcli, &mxa, heapref); 2305772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 2315772Sas200622 goto fault_exit; 2325772Sas200622 2335772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 2345772Sas200622 return (MLRPC_DRC_OK); 2355772Sas200622 2365772Sas200622 fault_exit: 2375772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 2385772Sas200622 return (rc); 2395772Sas200622 } 2405772Sas200622 2415772Sas200622 void 2425772Sas200622 mlrpc_c_free_heap(struct mlrpc_binding *mbind, mlrpc_heapref_t *heapref) 2435772Sas200622 { 2445772Sas200622 struct mlrpc_client *mcli = mbind->context; 2455772Sas200622 2465772Sas200622 (*mcli->xa_release)(mcli, heapref); 2475772Sas200622 } 2485772Sas200622 2495772Sas200622 static void 2505772Sas200622 mlrpc_c_init_hdr(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 2515772Sas200622 { 252*7619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 2535772Sas200622 2545772Sas200622 hdr->rpc_vers = 5; 2555772Sas200622 hdr->rpc_vers_minor = 0; 2565772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 2575772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII; 2585772Sas200622 #ifndef _BIG_ENDIAN 2595772Sas200622 hdr->packed_drep.intg_char_rep |= MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 2605772Sas200622 #endif 2615772Sas200622 /* hdr->frag_length */ 2625772Sas200622 hdr->auth_length = 0; 2635772Sas200622 hdr->call_id = mcli->next_call_id++; 2645772Sas200622 } 2655772Sas200622 2665772Sas200622 /* 2675772Sas200622 * mlrpc_c_remove_hdr 2685772Sas200622 * 2695772Sas200622 * Remove an RPC fragment header from the received data stream. 2705772Sas200622 * 2715772Sas200622 * Original RPC receive buffer: 2725772Sas200622 * |- frag1 -| |-frag M(partial)-| 2735772Sas200622 * +==================+=============+----+=================+ 2745772Sas200622 * | SmbTransact Rsp1 | SmbTransact | | SmbReadX RspN | 2755772Sas200622 * | (with RPC hdr) | Rsp2 | .. | (with RPC hdr) | 2765772Sas200622 * +-----+------------+-------------+ +-----+-----------+ 2775772Sas200622 * | hdr | data | data | .. | hdr | data | 2785772Sas200622 * +=====+============+=============+----+=====+===========+ 2795772Sas200622 * <------ 2805772Sas200622 * ^ ^ ^ 2815772Sas200622 * | | | 2825772Sas200622 * base_offset hdr data 2835772Sas200622 * 2845772Sas200622 * |-------------------------------------|-----------------| 2855772Sas200622 * offset len 2865772Sas200622 * 2875772Sas200622 * RPC receive buffer (after this call): 2885772Sas200622 * +==================+=============+----+===========+ 2895772Sas200622 * | SmbTransact Rsp1 | SmbTransact | | SmbReadX | 2905772Sas200622 * | (with RPC hdr) | Rsp2 | .. | RspN | 2915772Sas200622 * +-----+------------+-------------+ +-----------+ 2925772Sas200622 * | hdr | data | data | .. | data | 2935772Sas200622 * +=====+============+=============+----+===========+ 2945772Sas200622 */ 2955772Sas200622 static void 2965772Sas200622 mlrpc_c_remove_hdr(struct mlndr_stream *mlnds, int *nbytes) 2975772Sas200622 { 2985772Sas200622 char *hdr; 2995772Sas200622 char *data; 3005772Sas200622 3015772Sas200622 hdr = (char *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset; 3025772Sas200622 data = hdr + MLRPC_RSP_HDR_SIZE; 3035772Sas200622 *nbytes -= MLRPC_RSP_HDR_SIZE; 3045772Sas200622 3055772Sas200622 bcopy(data, hdr, *nbytes); 3065772Sas200622 mlnds->pdu_size -= MLRPC_RSP_HDR_SIZE; 3075772Sas200622 } 3085772Sas200622 3095772Sas200622 /* 3105772Sas200622 * mlrpc_c_get_frags 3115772Sas200622 * 3125772Sas200622 * A DCE RPC message that is larger than a single fragment is transmitted 3135772Sas200622 * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for 3145772Sas200622 * both Windows 2000 and 2003. 3155772Sas200622 * 3165772Sas200622 * Collect RPC fragments and append them to the receive stream buffer. 3175772Sas200622 * Each received fragment has a header, which we need to remove as we 3185772Sas200622 * build the full RPC PDU. 3195772Sas200622 * 3205772Sas200622 * The xa_read() calls will translate to SmbReadX requests. Note that 3215772Sas200622 * there is no correspondence between SmbReadX buffering and DCE RPC 3225772Sas200622 * fragment alignment. 3235772Sas200622 * 3245772Sas200622 * Return -1 on error. Otherwise, return the total data count of the 3255772Sas200622 * complete RPC response upon success. 3265772Sas200622 */ 3275772Sas200622 static int 3285772Sas200622 mlrpc_c_get_frags(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 3295772Sas200622 { 3305772Sas200622 struct mlndr_stream *mlnds = &mxa->recv_mlnds; 331*7619SJose.Borrego@Sun.COM ndr_common_header_t hdr; 3325772Sas200622 int frag_rcvd; 3335772Sas200622 int frag_size; 3345772Sas200622 int last_frag; 3355772Sas200622 int nbytes; 3365772Sas200622 3375772Sas200622 /* 3385772Sas200622 * The scan offest will be used to locate the frag header. 3395772Sas200622 */ 3405772Sas200622 mlnds->pdu_scan_offset = mlnds->pdu_base_offset + mlnds->pdu_size; 3415772Sas200622 3425772Sas200622 do { 3435772Sas200622 frag_rcvd = 0; 3445772Sas200622 3455772Sas200622 do { 3465772Sas200622 if ((nbytes = (*mcli->xa_read)(mcli, mxa)) < 0) 3475772Sas200622 return (-1); 3485772Sas200622 3495772Sas200622 if (frag_rcvd == 0) { 3505772Sas200622 mlrpc_decode_frag_hdr(mlnds, &hdr); 3515772Sas200622 3525772Sas200622 last_frag = MLRPC_IS_LAST_FRAG(hdr.pfc_flags); 3535772Sas200622 frag_size = hdr.frag_length 3545772Sas200622 - MLRPC_RSP_HDR_SIZE; 3555772Sas200622 3565772Sas200622 mlrpc_c_remove_hdr(mlnds, &nbytes); 3575772Sas200622 mlnds->pdu_scan_offset += frag_size; 3585772Sas200622 } 3595772Sas200622 3605772Sas200622 frag_rcvd += nbytes; 3615772Sas200622 3625772Sas200622 } while (frag_rcvd < frag_size); 3635772Sas200622 } while (!last_frag); 3645772Sas200622 3655772Sas200622 return (0); 3665772Sas200622 } 367