xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_client.c (revision 7619:0ad244464731)
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