1*5772Sas200622 /* 2*5772Sas200622 * CDDL HEADER START 3*5772Sas200622 * 4*5772Sas200622 * The contents of this file are subject to the terms of the 5*5772Sas200622 * Common Development and Distribution License (the "License"). 6*5772Sas200622 * You may not use this file except in compliance with the License. 7*5772Sas200622 * 8*5772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5772Sas200622 * or http://www.opensolaris.org/os/licensing. 10*5772Sas200622 * See the License for the specific language governing permissions 11*5772Sas200622 * and limitations under the License. 12*5772Sas200622 * 13*5772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14*5772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16*5772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17*5772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18*5772Sas200622 * 19*5772Sas200622 * CDDL HEADER END 20*5772Sas200622 */ 21*5772Sas200622 /* 22*5772Sas200622 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5772Sas200622 * Use is subject to license terms. 24*5772Sas200622 */ 25*5772Sas200622 26*5772Sas200622 #pragma ident "%Z%%M% %I% %E% SMI" 27*5772Sas200622 28*5772Sas200622 #include <sys/errno.h> 29*5772Sas200622 #include <string.h> 30*5772Sas200622 #include <strings.h> 31*5772Sas200622 32*5772Sas200622 #include <smbsrv/libsmb.h> 33*5772Sas200622 #include <smbsrv/ndr.h> 34*5772Sas200622 #include <smbsrv/mlrpc.h> 35*5772Sas200622 36*5772Sas200622 #define MLRPC_IS_LAST_FRAG(F) ((F) & MLRPC_PFC_LAST_FRAG) 37*5772Sas200622 #define MLRPC_DEFAULT_FRAGSZ 8192 38*5772Sas200622 39*5772Sas200622 static void mlrpc_c_init_hdr(struct mlrpc_client *, struct mlrpc_xaction *); 40*5772Sas200622 static int mlrpc_c_get_frags(struct mlrpc_client *, struct mlrpc_xaction *); 41*5772Sas200622 static void mlrpc_c_remove_hdr(struct mlndr_stream *, int *); 42*5772Sas200622 43*5772Sas200622 int 44*5772Sas200622 mlrpc_c_bind(struct mlrpc_client *mcli, char *service_name, 45*5772Sas200622 struct mlrpc_binding **ret_binding_p) 46*5772Sas200622 { 47*5772Sas200622 struct mlrpc_service *msvc; 48*5772Sas200622 struct mlrpc_binding *mbind; 49*5772Sas200622 struct mlrpc_xaction mxa; 50*5772Sas200622 mlrpcconn_bind_hdr_t *bhdr; 51*5772Sas200622 mlrpc_p_cont_elem_t *pce; 52*5772Sas200622 mlrpcconn_bind_ack_hdr_t *bahdr; 53*5772Sas200622 mlrpc_p_result_t *pre; 54*5772Sas200622 int rc; 55*5772Sas200622 56*5772Sas200622 bzero(&mxa, sizeof (mxa)); 57*5772Sas200622 58*5772Sas200622 msvc = mlrpc_find_service_by_name(service_name); 59*5772Sas200622 if (msvc == NULL) 60*5772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 61*5772Sas200622 62*5772Sas200622 mxa.binding_list = mcli->binding_list; 63*5772Sas200622 if ((mbind = mlrpc_new_binding(&mxa)) == NULL) 64*5772Sas200622 return (MLRPC_DRC_FAULT_API_BIND_NO_SLOTS); 65*5772Sas200622 66*5772Sas200622 mlrpc_c_init_hdr(mcli, &mxa); 67*5772Sas200622 68*5772Sas200622 bhdr = &mxa.send_hdr.bind_hdr; 69*5772Sas200622 bhdr->common_hdr.ptype = MLRPC_PTYPE_BIND; 70*5772Sas200622 bhdr->common_hdr.frag_length = sizeof (*bhdr); 71*5772Sas200622 bhdr->max_xmit_frag = MLRPC_DEFAULT_FRAGSZ; 72*5772Sas200622 bhdr->max_recv_frag = MLRPC_DEFAULT_FRAGSZ; 73*5772Sas200622 bhdr->assoc_group_id = 0; 74*5772Sas200622 bhdr->p_context_elem.n_context_elem = 1; 75*5772Sas200622 76*5772Sas200622 /* Assign presentation context id */ 77*5772Sas200622 pce = &bhdr->p_context_elem.p_cont_elem[0]; 78*5772Sas200622 pce->p_cont_id = mcli->next_p_cont_id++; 79*5772Sas200622 pce->n_transfer_syn = 1; 80*5772Sas200622 81*5772Sas200622 /* Set up UUIDs and versions from the service */ 82*5772Sas200622 pce->abstract_syntax.if_version = msvc->abstract_syntax_version; 83*5772Sas200622 rc = mlrpc_str_to_uuid(msvc->abstract_syntax_uuid, 84*5772Sas200622 &pce->abstract_syntax.if_uuid); 85*5772Sas200622 if (!rc) 86*5772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 87*5772Sas200622 88*5772Sas200622 pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version; 89*5772Sas200622 rc = mlrpc_str_to_uuid(msvc->transfer_syntax_uuid, 90*5772Sas200622 &pce->transfer_syntaxes[0].if_uuid); 91*5772Sas200622 if (!rc) 92*5772Sas200622 return (MLRPC_DRC_FAULT_API_SERVICE_INVALID); 93*5772Sas200622 94*5772Sas200622 /* Format and exchange the PDU */ 95*5772Sas200622 96*5772Sas200622 rc = (*mcli->xa_init)(mcli, &mxa, 0); 97*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 98*5772Sas200622 return (rc); 99*5772Sas200622 100*5772Sas200622 rc = mlrpc_encode_pdu_hdr(&mxa); 101*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 102*5772Sas200622 goto fault_exit; 103*5772Sas200622 104*5772Sas200622 rc = (*mcli->xa_exchange)(mcli, &mxa); 105*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 106*5772Sas200622 goto fault_exit; 107*5772Sas200622 108*5772Sas200622 rc = mlrpc_decode_pdu_hdr(&mxa); 109*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 110*5772Sas200622 goto fault_exit; 111*5772Sas200622 112*5772Sas200622 /* done with buffers */ 113*5772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 114*5772Sas200622 115*5772Sas200622 bahdr = &mxa.recv_hdr.bind_ack_hdr; 116*5772Sas200622 117*5772Sas200622 if (mxa.ptype != MLRPC_PTYPE_BIND_ACK) 118*5772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 119*5772Sas200622 120*5772Sas200622 if (bahdr->p_result_list.n_results != 1) 121*5772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 122*5772Sas200622 123*5772Sas200622 pre = &bahdr->p_result_list.p_results[0]; 124*5772Sas200622 125*5772Sas200622 if (pre->result != MLRPC_PCDR_ACCEPTANCE) 126*5772Sas200622 return (MLRPC_DRC_FAULT_RECEIVED_MALFORMED); 127*5772Sas200622 128*5772Sas200622 mbind->p_cont_id = pce->p_cont_id; 129*5772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_CLIENT; 130*5772Sas200622 mbind->context = mcli; 131*5772Sas200622 mbind->service = msvc; 132*5772Sas200622 mbind->instance_specific = 0; 133*5772Sas200622 134*5772Sas200622 *ret_binding_p = mbind; 135*5772Sas200622 return (MLRPC_DRC_OK); 136*5772Sas200622 137*5772Sas200622 fault_exit: 138*5772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 139*5772Sas200622 return (rc); 140*5772Sas200622 } 141*5772Sas200622 142*5772Sas200622 int 143*5772Sas200622 mlrpc_c_call(struct mlrpc_binding *mbind, int opnum, void *params, 144*5772Sas200622 mlrpc_heapref_t *heapref) 145*5772Sas200622 { 146*5772Sas200622 struct mlrpc_client *mcli = mbind->context; 147*5772Sas200622 struct mlrpc_service *msvc = mbind->service; 148*5772Sas200622 struct mlrpc_xaction mxa; 149*5772Sas200622 mlrpcconn_request_hdr_t *reqhdr; 150*5772Sas200622 mlrpcconn_common_header_t *rsphdr; 151*5772Sas200622 unsigned long recv_pdu_scan_offset; 152*5772Sas200622 int rc; 153*5772Sas200622 154*5772Sas200622 if (mlrpc_find_stub_in_svc(msvc, opnum) == NULL) 155*5772Sas200622 return (MLRPC_DRC_FAULT_API_OPNUM_INVALID); 156*5772Sas200622 157*5772Sas200622 bzero(&mxa, sizeof (mxa)); 158*5772Sas200622 mxa.ptype = MLRPC_PTYPE_REQUEST; 159*5772Sas200622 mxa.opnum = opnum; 160*5772Sas200622 mxa.binding = mbind; 161*5772Sas200622 162*5772Sas200622 mlrpc_c_init_hdr(mcli, &mxa); 163*5772Sas200622 164*5772Sas200622 reqhdr = &mxa.send_hdr.request_hdr; 165*5772Sas200622 reqhdr->common_hdr.ptype = MLRPC_PTYPE_REQUEST; 166*5772Sas200622 reqhdr->p_cont_id = mbind->p_cont_id; 167*5772Sas200622 reqhdr->opnum = opnum; 168*5772Sas200622 169*5772Sas200622 rc = (*mcli->xa_init)(mcli, &mxa, heapref->heap); 170*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 171*5772Sas200622 return (rc); 172*5772Sas200622 173*5772Sas200622 /* Reserve room for hdr */ 174*5772Sas200622 mxa.send_mlnds.pdu_scan_offset = sizeof (*reqhdr); 175*5772Sas200622 176*5772Sas200622 rc = mlrpc_encode_call(&mxa, params); 177*5772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 178*5772Sas200622 goto fault_exit; 179*5772Sas200622 180*5772Sas200622 mxa.send_mlnds.pdu_scan_offset = 0; 181*5772Sas200622 182*5772Sas200622 /* 183*5772Sas200622 * Now we have the PDU size, we need to set up the 184*5772Sas200622 * frag_length and calculate the alloc_hint. 185*5772Sas200622 */ 186*5772Sas200622 mxa.send_hdr.common_hdr.frag_length = mxa.send_mlnds.pdu_size; 187*5772Sas200622 reqhdr->alloc_hint = mxa.send_mlnds.pdu_size - 188*5772Sas200622 sizeof (mlrpcconn_request_hdr_t); 189*5772Sas200622 190*5772Sas200622 rc = mlrpc_encode_pdu_hdr(&mxa); 191*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 192*5772Sas200622 goto fault_exit; 193*5772Sas200622 194*5772Sas200622 rc = (*mcli->xa_exchange)(mcli, &mxa); 195*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 196*5772Sas200622 goto fault_exit; 197*5772Sas200622 198*5772Sas200622 rc = mlrpc_decode_pdu_hdr(&mxa); 199*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 200*5772Sas200622 goto fault_exit; 201*5772Sas200622 202*5772Sas200622 if (mxa.ptype != MLRPC_PTYPE_RESPONSE) { 203*5772Sas200622 rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED; 204*5772Sas200622 goto fault_exit; 205*5772Sas200622 } 206*5772Sas200622 207*5772Sas200622 rsphdr = &mxa.recv_hdr.common_hdr; 208*5772Sas200622 209*5772Sas200622 if (!MLRPC_IS_LAST_FRAG(rsphdr->pfc_flags)) { 210*5772Sas200622 /* 211*5772Sas200622 * This is a multi-fragment response. 212*5772Sas200622 * Preserve the current scan offset while getting 213*5772Sas200622 * fragments so that we can continue afterward 214*5772Sas200622 * as if we had received the entire response as 215*5772Sas200622 * a single PDU. 216*5772Sas200622 */ 217*5772Sas200622 recv_pdu_scan_offset = mxa.recv_mlnds.pdu_scan_offset; 218*5772Sas200622 219*5772Sas200622 if (mlrpc_c_get_frags(mcli, &mxa) < 0) { 220*5772Sas200622 rc = MLRPC_DRC_FAULT_RECEIVED_MALFORMED; 221*5772Sas200622 goto fault_exit; 222*5772Sas200622 } 223*5772Sas200622 224*5772Sas200622 mxa.recv_mlnds.pdu_scan_offset = recv_pdu_scan_offset; 225*5772Sas200622 } 226*5772Sas200622 227*5772Sas200622 rc = mlrpc_decode_return(&mxa, params); 228*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 229*5772Sas200622 goto fault_exit; 230*5772Sas200622 231*5772Sas200622 rc = (*mcli->xa_preserve)(mcli, &mxa, heapref); 232*5772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 233*5772Sas200622 goto fault_exit; 234*5772Sas200622 235*5772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 236*5772Sas200622 return (MLRPC_DRC_OK); 237*5772Sas200622 238*5772Sas200622 fault_exit: 239*5772Sas200622 (*mcli->xa_destruct)(mcli, &mxa); 240*5772Sas200622 return (rc); 241*5772Sas200622 } 242*5772Sas200622 243*5772Sas200622 void 244*5772Sas200622 mlrpc_c_free_heap(struct mlrpc_binding *mbind, mlrpc_heapref_t *heapref) 245*5772Sas200622 { 246*5772Sas200622 struct mlrpc_client *mcli = mbind->context; 247*5772Sas200622 248*5772Sas200622 (*mcli->xa_release)(mcli, heapref); 249*5772Sas200622 } 250*5772Sas200622 251*5772Sas200622 static void 252*5772Sas200622 mlrpc_c_init_hdr(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 253*5772Sas200622 { 254*5772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 255*5772Sas200622 256*5772Sas200622 hdr->rpc_vers = 5; 257*5772Sas200622 hdr->rpc_vers_minor = 0; 258*5772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 259*5772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII; 260*5772Sas200622 #ifndef _BIG_ENDIAN 261*5772Sas200622 hdr->packed_drep.intg_char_rep |= MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 262*5772Sas200622 #endif 263*5772Sas200622 /* hdr->frag_length */ 264*5772Sas200622 hdr->auth_length = 0; 265*5772Sas200622 hdr->call_id = mcli->next_call_id++; 266*5772Sas200622 } 267*5772Sas200622 268*5772Sas200622 /* 269*5772Sas200622 * mlrpc_c_remove_hdr 270*5772Sas200622 * 271*5772Sas200622 * Remove an RPC fragment header from the received data stream. 272*5772Sas200622 * 273*5772Sas200622 * Original RPC receive buffer: 274*5772Sas200622 * |- frag1 -| |-frag M(partial)-| 275*5772Sas200622 * +==================+=============+----+=================+ 276*5772Sas200622 * | SmbTransact Rsp1 | SmbTransact | | SmbReadX RspN | 277*5772Sas200622 * | (with RPC hdr) | Rsp2 | .. | (with RPC hdr) | 278*5772Sas200622 * +-----+------------+-------------+ +-----+-----------+ 279*5772Sas200622 * | hdr | data | data | .. | hdr | data | 280*5772Sas200622 * +=====+============+=============+----+=====+===========+ 281*5772Sas200622 * <------ 282*5772Sas200622 * ^ ^ ^ 283*5772Sas200622 * | | | 284*5772Sas200622 * base_offset hdr data 285*5772Sas200622 * 286*5772Sas200622 * |-------------------------------------|-----------------| 287*5772Sas200622 * offset len 288*5772Sas200622 * 289*5772Sas200622 * RPC receive buffer (after this call): 290*5772Sas200622 * +==================+=============+----+===========+ 291*5772Sas200622 * | SmbTransact Rsp1 | SmbTransact | | SmbReadX | 292*5772Sas200622 * | (with RPC hdr) | Rsp2 | .. | RspN | 293*5772Sas200622 * +-----+------------+-------------+ +-----------+ 294*5772Sas200622 * | hdr | data | data | .. | data | 295*5772Sas200622 * +=====+============+=============+----+===========+ 296*5772Sas200622 */ 297*5772Sas200622 static void 298*5772Sas200622 mlrpc_c_remove_hdr(struct mlndr_stream *mlnds, int *nbytes) 299*5772Sas200622 { 300*5772Sas200622 char *hdr; 301*5772Sas200622 char *data; 302*5772Sas200622 303*5772Sas200622 hdr = (char *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset; 304*5772Sas200622 data = hdr + MLRPC_RSP_HDR_SIZE; 305*5772Sas200622 *nbytes -= MLRPC_RSP_HDR_SIZE; 306*5772Sas200622 307*5772Sas200622 bcopy(data, hdr, *nbytes); 308*5772Sas200622 mlnds->pdu_size -= MLRPC_RSP_HDR_SIZE; 309*5772Sas200622 } 310*5772Sas200622 311*5772Sas200622 /* 312*5772Sas200622 * mlrpc_c_get_frags 313*5772Sas200622 * 314*5772Sas200622 * A DCE RPC message that is larger than a single fragment is transmitted 315*5772Sas200622 * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for 316*5772Sas200622 * both Windows 2000 and 2003. 317*5772Sas200622 * 318*5772Sas200622 * Collect RPC fragments and append them to the receive stream buffer. 319*5772Sas200622 * Each received fragment has a header, which we need to remove as we 320*5772Sas200622 * build the full RPC PDU. 321*5772Sas200622 * 322*5772Sas200622 * The xa_read() calls will translate to SmbReadX requests. Note that 323*5772Sas200622 * there is no correspondence between SmbReadX buffering and DCE RPC 324*5772Sas200622 * fragment alignment. 325*5772Sas200622 * 326*5772Sas200622 * Return -1 on error. Otherwise, return the total data count of the 327*5772Sas200622 * complete RPC response upon success. 328*5772Sas200622 */ 329*5772Sas200622 static int 330*5772Sas200622 mlrpc_c_get_frags(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 331*5772Sas200622 { 332*5772Sas200622 struct mlndr_stream *mlnds = &mxa->recv_mlnds; 333*5772Sas200622 mlrpcconn_common_header_t hdr; 334*5772Sas200622 int frag_rcvd; 335*5772Sas200622 int frag_size; 336*5772Sas200622 int last_frag; 337*5772Sas200622 int nbytes; 338*5772Sas200622 339*5772Sas200622 /* 340*5772Sas200622 * The scan offest will be used to locate the frag header. 341*5772Sas200622 */ 342*5772Sas200622 mlnds->pdu_scan_offset = mlnds->pdu_base_offset + mlnds->pdu_size; 343*5772Sas200622 344*5772Sas200622 do { 345*5772Sas200622 frag_rcvd = 0; 346*5772Sas200622 347*5772Sas200622 do { 348*5772Sas200622 if ((nbytes = (*mcli->xa_read)(mcli, mxa)) < 0) 349*5772Sas200622 return (-1); 350*5772Sas200622 351*5772Sas200622 if (frag_rcvd == 0) { 352*5772Sas200622 mlrpc_decode_frag_hdr(mlnds, &hdr); 353*5772Sas200622 354*5772Sas200622 last_frag = MLRPC_IS_LAST_FRAG(hdr.pfc_flags); 355*5772Sas200622 frag_size = hdr.frag_length 356*5772Sas200622 - MLRPC_RSP_HDR_SIZE; 357*5772Sas200622 358*5772Sas200622 mlrpc_c_remove_hdr(mlnds, &nbytes); 359*5772Sas200622 mlnds->pdu_scan_offset += frag_size; 360*5772Sas200622 } 361*5772Sas200622 362*5772Sas200622 frag_rcvd += nbytes; 363*5772Sas200622 364*5772Sas200622 } while (frag_rcvd < frag_size); 365*5772Sas200622 } while (!last_frag); 366*5772Sas200622 367*5772Sas200622 return (0); 368*5772Sas200622 } 369