13299f39fSGordon Ross /*
23299f39fSGordon Ross  * CDDL HEADER START
33299f39fSGordon Ross  *
43299f39fSGordon Ross  * The contents of this file are subject to the terms of the
53299f39fSGordon Ross  * Common Development and Distribution License (the "License").
63299f39fSGordon Ross  * You may not use this file except in compliance with the License.
73299f39fSGordon Ross  *
83299f39fSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93299f39fSGordon Ross  * or http://www.opensolaris.org/os/licensing.
103299f39fSGordon Ross  * See the License for the specific language governing permissions
113299f39fSGordon Ross  * and limitations under the License.
123299f39fSGordon Ross  *
133299f39fSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
143299f39fSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153299f39fSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
163299f39fSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
173299f39fSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
183299f39fSGordon Ross  *
193299f39fSGordon Ross  * CDDL HEADER END
203299f39fSGordon Ross  */
213299f39fSGordon Ross /*
223299f39fSGordon Ross  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
233299f39fSGordon Ross  * Use is subject to license terms.
243299f39fSGordon Ross  *
25*ce8560eeSMatt Barden  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
263299f39fSGordon Ross  */
273299f39fSGordon Ross 
283299f39fSGordon Ross #include <sys/errno.h>
293299f39fSGordon Ross #include <string.h>
303299f39fSGordon Ross #include <strings.h>
313299f39fSGordon Ross 
323299f39fSGordon Ross #include <libmlrpc.h>
333299f39fSGordon Ross 
343299f39fSGordon Ross #define	NDR_DEFAULT_FRAGSZ	8192
353299f39fSGordon Ross #define	NDR_MULTI_FRAGSZ	(60 * 1024)
363299f39fSGordon Ross 
373299f39fSGordon Ross static void ndr_clnt_init_hdr(ndr_client_t *, ndr_xa_t *);
383299f39fSGordon Ross static int ndr_clnt_get_frags(ndr_client_t *, ndr_xa_t *);
393299f39fSGordon Ross static int ndr_clnt_get_frag(ndr_client_t *, ndr_xa_t *, ndr_common_header_t *);
403299f39fSGordon Ross 
413299f39fSGordon Ross int
ndr_clnt_bind(ndr_client_t * clnt,ndr_service_t * msvc,ndr_binding_t ** ret_binding_p)423299f39fSGordon Ross ndr_clnt_bind(ndr_client_t *clnt, ndr_service_t *msvc,
433299f39fSGordon Ross     ndr_binding_t **ret_binding_p)
443299f39fSGordon Ross {
453299f39fSGordon Ross 	ndr_binding_t		*mbind;
463299f39fSGordon Ross 	ndr_xa_t		mxa;
473299f39fSGordon Ross 	ndr_bind_hdr_t		*bhdr;
48*ce8560eeSMatt Barden 	ndr_common_header_t	*hdr;
493299f39fSGordon Ross 	ndr_p_cont_elem_t	*pce;
503299f39fSGordon Ross 	ndr_bind_ack_hdr_t	*bahdr;
513299f39fSGordon Ross 	ndr_p_result_t		*pre;
523299f39fSGordon Ross 	int			rc;
533299f39fSGordon Ross 
543299f39fSGordon Ross 	bzero(&mxa, sizeof (mxa));
553299f39fSGordon Ross 
563299f39fSGordon Ross 	mxa.binding_list = clnt->binding_list;
573299f39fSGordon Ross 	if ((mbind = ndr_svc_new_binding(&mxa)) == NULL)
583299f39fSGordon Ross 		return (NDR_DRC_FAULT_API_BIND_NO_SLOTS);
593299f39fSGordon Ross 
603299f39fSGordon Ross 	ndr_clnt_init_hdr(clnt, &mxa);
613299f39fSGordon Ross 
623299f39fSGordon Ross 	bhdr = &mxa.send_hdr.bind_hdr;
63*ce8560eeSMatt Barden 	hdr = &mxa.send_hdr.bind_hdr.common_hdr;
64*ce8560eeSMatt Barden 	hdr->ptype = NDR_PTYPE_BIND;
653299f39fSGordon Ross 	bhdr->max_xmit_frag = NDR_DEFAULT_FRAGSZ;
663299f39fSGordon Ross 	bhdr->max_recv_frag = NDR_DEFAULT_FRAGSZ;
673299f39fSGordon Ross 	bhdr->assoc_group_id = 0;
683299f39fSGordon Ross 	bhdr->p_context_elem.n_context_elem = 1;
693299f39fSGordon Ross 
703299f39fSGordon Ross 	/* Assign presentation context id */
713299f39fSGordon Ross 	pce = &bhdr->p_context_elem.p_cont_elem[0];
723299f39fSGordon Ross 	pce->p_cont_id = clnt->next_p_cont_id++;
733299f39fSGordon Ross 	pce->n_transfer_syn = 1;
743299f39fSGordon Ross 
753299f39fSGordon Ross 	/* Set up UUIDs and versions from the service */
763299f39fSGordon Ross 	pce->abstract_syntax.if_version = msvc->abstract_syntax_version;
773299f39fSGordon Ross 	rc = ndr_uuid_parse(msvc->abstract_syntax_uuid,
783299f39fSGordon Ross 	    &pce->abstract_syntax.if_uuid);
793299f39fSGordon Ross 	if (rc != 0)
803299f39fSGordon Ross 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
813299f39fSGordon Ross 
823299f39fSGordon Ross 	pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version;
833299f39fSGordon Ross 	rc = ndr_uuid_parse(msvc->transfer_syntax_uuid,
843299f39fSGordon Ross 	    &pce->transfer_syntaxes[0].if_uuid);
853299f39fSGordon Ross 	if (rc != 0)
863299f39fSGordon Ross 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
873299f39fSGordon Ross 
883299f39fSGordon Ross 	/* Format and exchange the PDU */
893299f39fSGordon Ross 
903299f39fSGordon Ross 	if ((*clnt->xa_init)(clnt, &mxa) < 0)
913299f39fSGordon Ross 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
923299f39fSGordon Ross 
93*ce8560eeSMatt Barden 	/* Reserve room for hdr */
94*ce8560eeSMatt Barden 	mxa.send_nds.pdu_scan_offset = sizeof (*bhdr);
95*ce8560eeSMatt Barden 
96*ce8560eeSMatt Barden 	/* GSS_Init_sec_context */
97*ce8560eeSMatt Barden 	rc = ndr_add_sec_context(&clnt->auth_ctx, &mxa);
98*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
99*ce8560eeSMatt Barden 		goto fault_exit;
100*ce8560eeSMatt Barden 
101*ce8560eeSMatt Barden 	rc = ndr_encode_pdu_auth(&mxa);
102*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
103*ce8560eeSMatt Barden 		goto fault_exit;
104*ce8560eeSMatt Barden 
105*ce8560eeSMatt Barden 	/*
106*ce8560eeSMatt Barden 	 * If we have auth data, then pdu_size has been initialized.
107*ce8560eeSMatt Barden 	 * Otherwise, it hasn't.
108*ce8560eeSMatt Barden 	 */
109*ce8560eeSMatt Barden 	if (hdr->auth_length == 0)
110*ce8560eeSMatt Barden 		hdr->frag_length = sizeof (*bhdr);
111*ce8560eeSMatt Barden 	else
112*ce8560eeSMatt Barden 		hdr->frag_length = mxa.send_nds.pdu_size;
113*ce8560eeSMatt Barden 
114*ce8560eeSMatt Barden 	/* Reset scan_offset to header */
115*ce8560eeSMatt Barden 	mxa.send_nds.pdu_scan_offset = 0;
116*ce8560eeSMatt Barden 
1173299f39fSGordon Ross 	rc = ndr_encode_pdu_hdr(&mxa);
1183299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
1193299f39fSGordon Ross 		goto fault_exit;
1203299f39fSGordon Ross 
1213299f39fSGordon Ross 	if ((*clnt->xa_exchange)(clnt, &mxa) < 0) {
1223299f39fSGordon Ross 		rc = NDR_DRC_FAULT_SEND_FAILED;
1233299f39fSGordon Ross 		goto fault_exit;
1243299f39fSGordon Ross 	}
1253299f39fSGordon Ross 
1263299f39fSGordon Ross 	rc = ndr_decode_pdu_hdr(&mxa);
1273299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
1283299f39fSGordon Ross 		goto fault_exit;
1293299f39fSGordon Ross 
130*ce8560eeSMatt Barden 	rc = ndr_decode_pdu_auth(&mxa);
131*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
132*ce8560eeSMatt Barden 		goto fault_exit;
1333299f39fSGordon Ross 
1343299f39fSGordon Ross 	bahdr = &mxa.recv_hdr.bind_ack_hdr;
1353299f39fSGordon Ross 
136*ce8560eeSMatt Barden 	if (mxa.ptype != NDR_PTYPE_BIND_ACK) {
137*ce8560eeSMatt Barden 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
138*ce8560eeSMatt Barden 		goto fault_exit;
139*ce8560eeSMatt Barden 	}
1403299f39fSGordon Ross 
141*ce8560eeSMatt Barden 	if (bahdr->p_result_list.n_results != 1) {
142*ce8560eeSMatt Barden 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
143*ce8560eeSMatt Barden 		goto fault_exit;
144*ce8560eeSMatt Barden 	}
1453299f39fSGordon Ross 
1463299f39fSGordon Ross 	pre = &bahdr->p_result_list.p_results[0];
1473299f39fSGordon Ross 
148*ce8560eeSMatt Barden 	if (pre->result != NDR_PCDR_ACCEPTANCE) {
149*ce8560eeSMatt Barden 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
150*ce8560eeSMatt Barden 		goto fault_exit;
151*ce8560eeSMatt Barden 	}
152*ce8560eeSMatt Barden 
153*ce8560eeSMatt Barden 	/* GSS_init_sec_context 2 */
154*ce8560eeSMatt Barden 	rc = ndr_recv_sec_context(&clnt->auth_ctx, &mxa);
155*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
156*ce8560eeSMatt Barden 		goto fault_exit;
157*ce8560eeSMatt Barden 
158*ce8560eeSMatt Barden 	/* done with buffers */
159*ce8560eeSMatt Barden 	(*clnt->xa_destruct)(clnt, &mxa);
1603299f39fSGordon Ross 
1613299f39fSGordon Ross 	mbind->p_cont_id = pce->p_cont_id;
1623299f39fSGordon Ross 	mbind->which_side = NDR_BIND_SIDE_CLIENT;
1633299f39fSGordon Ross 	mbind->clnt = clnt;
1643299f39fSGordon Ross 	mbind->service = msvc;
1653299f39fSGordon Ross 	mbind->instance_specific = 0;
1663299f39fSGordon Ross 
1673299f39fSGordon Ross 	*ret_binding_p = mbind;
1683299f39fSGordon Ross 	return (NDR_DRC_OK);
1693299f39fSGordon Ross 
1703299f39fSGordon Ross fault_exit:
1713299f39fSGordon Ross 	(*clnt->xa_destruct)(clnt, &mxa);
1723299f39fSGordon Ross 	return (rc);
1733299f39fSGordon Ross }
1743299f39fSGordon Ross 
1753299f39fSGordon Ross int
ndr_clnt_call(ndr_binding_t * mbind,int opnum,void * params)1763299f39fSGordon Ross ndr_clnt_call(ndr_binding_t *mbind, int opnum, void *params)
1773299f39fSGordon Ross {
1783299f39fSGordon Ross 	ndr_client_t		*clnt = mbind->clnt;
1793299f39fSGordon Ross 	ndr_xa_t		mxa;
1803299f39fSGordon Ross 	ndr_request_hdr_t	*reqhdr;
1813299f39fSGordon Ross 	ndr_common_header_t	*rsphdr;
182*ce8560eeSMatt Barden 	unsigned long		recv_pdu_scan_offset, recv_pdu_size;
1833299f39fSGordon Ross 	int			rc;
1843299f39fSGordon Ross 
1853299f39fSGordon Ross 	bzero(&mxa, sizeof (mxa));
1863299f39fSGordon Ross 	mxa.ptype = NDR_PTYPE_REQUEST;
1873299f39fSGordon Ross 	mxa.opnum = opnum;
1883299f39fSGordon Ross 	mxa.binding = mbind;
1893299f39fSGordon Ross 
1903299f39fSGordon Ross 	ndr_clnt_init_hdr(clnt, &mxa);
1913299f39fSGordon Ross 
1923299f39fSGordon Ross 	reqhdr = &mxa.send_hdr.request_hdr;
1933299f39fSGordon Ross 	reqhdr->common_hdr.ptype = NDR_PTYPE_REQUEST;
1943299f39fSGordon Ross 	reqhdr->p_cont_id = mbind->p_cont_id;
1953299f39fSGordon Ross 	reqhdr->opnum = opnum;
1963299f39fSGordon Ross 
1973299f39fSGordon Ross 	rc = (*clnt->xa_init)(clnt, &mxa);
1983299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
1993299f39fSGordon Ross 		return (rc);
2003299f39fSGordon Ross 
2013299f39fSGordon Ross 	/* Reserve room for hdr */
2023299f39fSGordon Ross 	mxa.send_nds.pdu_scan_offset = sizeof (*reqhdr);
203*ce8560eeSMatt Barden 	/* pdu_scan_offset now points to start of stub */
204*ce8560eeSMatt Barden 	mxa.send_nds.pdu_body_offset = mxa.send_nds.pdu_scan_offset;
2053299f39fSGordon Ross 
2063299f39fSGordon Ross 	rc = ndr_encode_call(&mxa, params);
2073299f39fSGordon Ross 	if (!NDR_DRC_IS_OK(rc))
2083299f39fSGordon Ross 		goto fault_exit;
2093299f39fSGordon Ross 
210*ce8560eeSMatt Barden 	/*
211*ce8560eeSMatt Barden 	 * With the Stub data encoded, calculate the alloc_hint
212*ce8560eeSMatt Barden 	 * before we add padding or auth data.
213*ce8560eeSMatt Barden 	 */
214*ce8560eeSMatt Barden 	reqhdr->alloc_hint = mxa.send_nds.pdu_size -
215*ce8560eeSMatt Barden 	    sizeof (ndr_request_hdr_t);
216*ce8560eeSMatt Barden 
217*ce8560eeSMatt Barden 	/* GSS_WrapEx/VerifyMICEx */
218*ce8560eeSMatt Barden 	rc = ndr_add_auth(&clnt->auth_ctx, &mxa);
219*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
220*ce8560eeSMatt Barden 		goto fault_exit;
221*ce8560eeSMatt Barden 
222*ce8560eeSMatt Barden 	rc = ndr_encode_pdu_auth(&mxa);
223*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
224*ce8560eeSMatt Barden 		goto fault_exit;
2253299f39fSGordon Ross 
2263299f39fSGordon Ross 	/*
2273299f39fSGordon Ross 	 * Now we have the PDU size, we need to set up the
228*ce8560eeSMatt Barden 	 * frag_length.
229*ce8560eeSMatt Barden 	 * Also reset pdu_scan_offset to header.
2303299f39fSGordon Ross 	 */
2313299f39fSGordon Ross 	mxa.send_hdr.common_hdr.frag_length = mxa.send_nds.pdu_size;
232*ce8560eeSMatt Barden 	mxa.send_nds.pdu_scan_offset = 0;
2333299f39fSGordon Ross 
2343299f39fSGordon Ross 	rc = ndr_encode_pdu_hdr(&mxa);
2353299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
2363299f39fSGordon Ross 		goto fault_exit;
2373299f39fSGordon Ross 
2383299f39fSGordon Ross 	rc = (*clnt->xa_exchange)(clnt, &mxa);
2393299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
2403299f39fSGordon Ross 		goto fault_exit;
2413299f39fSGordon Ross 
2423299f39fSGordon Ross 	rc = ndr_decode_pdu_hdr(&mxa);
2433299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
2443299f39fSGordon Ross 		goto fault_exit;
2453299f39fSGordon Ross 
2463299f39fSGordon Ross 	if (mxa.ptype != NDR_PTYPE_RESPONSE) {
2473299f39fSGordon Ross 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
2483299f39fSGordon Ross 		goto fault_exit;
2493299f39fSGordon Ross 	}
2503299f39fSGordon Ross 
251*ce8560eeSMatt Barden 	rc = ndr_decode_pdu_auth(&mxa);
252*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
253*ce8560eeSMatt Barden 		goto fault_exit;
254*ce8560eeSMatt Barden 
255*ce8560eeSMatt Barden 	rc = ndr_check_auth(&clnt->auth_ctx, &mxa);
256*ce8560eeSMatt Barden 	if (NDR_DRC_IS_FAULT(rc))
257*ce8560eeSMatt Barden 		goto fault_exit;
258*ce8560eeSMatt Barden 
2593299f39fSGordon Ross 	rsphdr = &mxa.recv_hdr.common_hdr;
2603299f39fSGordon Ross 
2613299f39fSGordon Ross 	if (!NDR_IS_LAST_FRAG(rsphdr->pfc_flags)) {
2623299f39fSGordon Ross 		/*
2633299f39fSGordon Ross 		 * This is a multi-fragment response.
264*ce8560eeSMatt Barden 		 * Preserve the current body offset while getting
2653299f39fSGordon Ross 		 * fragments so that we can continue afterward
2663299f39fSGordon Ross 		 * as if we had received the entire response as
2673299f39fSGordon Ross 		 * a single PDU.
268*ce8560eeSMatt Barden 		 *
269*ce8560eeSMatt Barden 		 * GROW_PDU trashes pdu_size; reset it afterwards.
2703299f39fSGordon Ross 		 */
271*ce8560eeSMatt Barden 		recv_pdu_size = mxa.recv_nds.pdu_size;
2723299f39fSGordon Ross 		(void) NDS_GROW_PDU(&mxa.recv_nds, NDR_MULTI_FRAGSZ, NULL);
2733299f39fSGordon Ross 
274*ce8560eeSMatt Barden 		/*
275*ce8560eeSMatt Barden 		 * pdu_scan_offset needs to be the first byte after the first
276*ce8560eeSMatt Barden 		 * fragment in pdu_base_addr (minus the sec_trailer).
277*ce8560eeSMatt Barden 		 *
278*ce8560eeSMatt Barden 		 * pdu_size needs to be all of the (usable) data we've
279*ce8560eeSMatt Barden 		 * received thus far.
280*ce8560eeSMatt Barden 		 */
281*ce8560eeSMatt Barden 		recv_pdu_scan_offset = mxa.recv_nds.pdu_body_offset;
282*ce8560eeSMatt Barden 		mxa.recv_nds.pdu_scan_offset = mxa.recv_nds.pdu_body_offset +
283*ce8560eeSMatt Barden 		    mxa.recv_nds.pdu_body_size - mxa.recv_auth.auth_pad_len;
284*ce8560eeSMatt Barden 		mxa.recv_nds.pdu_size = recv_pdu_size;
2853299f39fSGordon Ross 
286*ce8560eeSMatt Barden 		rc = ndr_clnt_get_frags(clnt, &mxa);
287*ce8560eeSMatt Barden 		if (NDR_DRC_IS_FAULT(rc))
2883299f39fSGordon Ross 			goto fault_exit;
2893299f39fSGordon Ross 
2903299f39fSGordon Ross 		mxa.recv_nds.pdu_scan_offset = recv_pdu_scan_offset;
2913299f39fSGordon Ross 	}
2923299f39fSGordon Ross 
2933299f39fSGordon Ross 	rc = ndr_decode_return(&mxa, params);
2943299f39fSGordon Ross 	if (NDR_DRC_IS_FAULT(rc))
2953299f39fSGordon Ross 		goto fault_exit;
2963299f39fSGordon Ross 
2973299f39fSGordon Ross 	(*clnt->xa_preserve)(clnt, &mxa);
2983299f39fSGordon Ross 	(*clnt->xa_destruct)(clnt, &mxa);
2993299f39fSGordon Ross 	return (NDR_DRC_OK);
3003299f39fSGordon Ross 
3013299f39fSGordon Ross fault_exit:
302*ce8560eeSMatt Barden 	ndr_show_hdr(&mxa.send_hdr.common_hdr);
303*ce8560eeSMatt Barden 	nds_show_state(&mxa.send_nds);
304*ce8560eeSMatt Barden 	if (mxa.send_hdr.common_hdr.auth_length != 0)
305*ce8560eeSMatt Barden 		ndr_show_auth(&mxa.send_auth);
306*ce8560eeSMatt Barden 
307*ce8560eeSMatt Barden 	ndr_show_hdr(&mxa.recv_hdr.common_hdr);
308*ce8560eeSMatt Barden 	nds_show_state(&mxa.recv_nds);
309*ce8560eeSMatt Barden 	if (mxa.recv_hdr.common_hdr.auth_length != 0)
310*ce8560eeSMatt Barden 		ndr_show_auth(&mxa.recv_auth);
3113299f39fSGordon Ross 	(*clnt->xa_destruct)(clnt, &mxa);
3123299f39fSGordon Ross 	return (rc);
3133299f39fSGordon Ross }
3143299f39fSGordon Ross 
3153299f39fSGordon Ross void
ndr_clnt_free_heap(ndr_client_t * clnt)3163299f39fSGordon Ross ndr_clnt_free_heap(ndr_client_t *clnt)
3173299f39fSGordon Ross {
3183299f39fSGordon Ross 	(*clnt->xa_release)(clnt);
3193299f39fSGordon Ross }
3203299f39fSGordon Ross 
3213299f39fSGordon Ross static void
ndr_clnt_init_hdr(ndr_client_t * clnt,ndr_xa_t * mxa)3223299f39fSGordon Ross ndr_clnt_init_hdr(ndr_client_t *clnt, ndr_xa_t *mxa)
3233299f39fSGordon Ross {
3243299f39fSGordon Ross 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
3253299f39fSGordon Ross 
3263299f39fSGordon Ross 	hdr->rpc_vers = 5;
3273299f39fSGordon Ross 	hdr->rpc_vers_minor = 0;
3283299f39fSGordon Ross 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
3293299f39fSGordon Ross 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII;
3303299f39fSGordon Ross #ifndef _BIG_ENDIAN
3313299f39fSGordon Ross 	hdr->packed_drep.intg_char_rep |= NDR_REPLAB_INTG_LITTLE_ENDIAN;
3323299f39fSGordon Ross #endif
3333299f39fSGordon Ross 	/* hdr->frag_length */
3343299f39fSGordon Ross 	hdr->auth_length = 0;
3353299f39fSGordon Ross 	hdr->call_id = clnt->next_call_id++;
3363299f39fSGordon Ross }
3373299f39fSGordon Ross 
3383299f39fSGordon Ross /*
3393299f39fSGordon Ross  * ndr_clnt_get_frags
3403299f39fSGordon Ross  *
3413299f39fSGordon Ross  * A DCE RPC message that is larger than a single fragment is transmitted
3423299f39fSGordon Ross  * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for
3433299f39fSGordon Ross  * both Windows 2000 and 2003.
3443299f39fSGordon Ross  *
3453299f39fSGordon Ross  * Collect RPC fragments and append them to the receive stream buffer.
3463299f39fSGordon Ross  * Each received fragment has a header, which we need to remove as we
3473299f39fSGordon Ross  * build the full RPC PDU.  The scan offset is used to track frag headers.
3483299f39fSGordon Ross  */
3493299f39fSGordon Ross static int
ndr_clnt_get_frags(ndr_client_t * clnt,ndr_xa_t * mxa)3503299f39fSGordon Ross ndr_clnt_get_frags(ndr_client_t *clnt, ndr_xa_t *mxa)
3513299f39fSGordon Ross {
3523299f39fSGordon Ross 	ndr_stream_t *nds = &mxa->recv_nds;
3533299f39fSGordon Ross 	ndr_common_header_t hdr;
3543299f39fSGordon Ross 	int frag_size;
3553299f39fSGordon Ross 	int last_frag;
356*ce8560eeSMatt Barden 	int rc;
3573299f39fSGordon Ross 
3583299f39fSGordon Ross 	do {
3593299f39fSGordon Ross 		if (ndr_clnt_get_frag(clnt, mxa, &hdr) < 0) {
3603299f39fSGordon Ross 			nds_show_state(nds);
361*ce8560eeSMatt Barden 			return (NDR_DRC_FAULT_RECEIVED_RUNT);
3623299f39fSGordon Ross 		}
3633299f39fSGordon Ross 
3643299f39fSGordon Ross 		last_frag = NDR_IS_LAST_FRAG(hdr.pfc_flags);
3653299f39fSGordon Ross 		frag_size = hdr.frag_length;
3663299f39fSGordon Ross 
367*ce8560eeSMatt Barden 		/*
368*ce8560eeSMatt Barden 		 * ndr_clnt_get_frag() doesn't change pdu_scan_offset.
369*ce8560eeSMatt Barden 		 */
3703299f39fSGordon Ross 		if (frag_size > (nds->pdu_size - nds->pdu_scan_offset)) {
3713299f39fSGordon Ross 			nds_show_state(nds);
372*ce8560eeSMatt Barden 			return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
3733299f39fSGordon Ross 		}
3743299f39fSGordon Ross 
375*ce8560eeSMatt Barden 		if (hdr.auth_length != 0 && hdr.auth_length >
376*ce8560eeSMatt Barden 		    (hdr.frag_length - nds->pdu_hdr_size - SEC_TRAILER_SIZE))
377*ce8560eeSMatt Barden 			return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
378*ce8560eeSMatt Barden 
379*ce8560eeSMatt Barden 		rc = ndr_decode_pdu_auth(mxa);
380*ce8560eeSMatt Barden 		if (NDR_DRC_IS_FAULT(rc))
381*ce8560eeSMatt Barden 			return (rc);
382*ce8560eeSMatt Barden 
383*ce8560eeSMatt Barden 		rc = ndr_check_auth(&clnt->auth_ctx, mxa);
384*ce8560eeSMatt Barden 		if (NDR_DRC_IS_FAULT(rc))
385*ce8560eeSMatt Barden 			return (rc);
386*ce8560eeSMatt Barden 
387*ce8560eeSMatt Barden 		/*
388*ce8560eeSMatt Barden 		 * Headers, Auth Padding, and auth data shouldn't be kept
389*ce8560eeSMatt Barden 		 * from fragments.
390*ce8560eeSMatt Barden 		 */
3913299f39fSGordon Ross 		ndr_remove_frag_hdr(nds);
392*ce8560eeSMatt Barden 		nds->pdu_scan_offset +=
393*ce8560eeSMatt Barden 		    nds->pdu_body_size - mxa->recv_auth.auth_pad_len;
3943299f39fSGordon Ross 	} while (!last_frag);
3953299f39fSGordon Ross 
3963299f39fSGordon Ross 	return (0);
3973299f39fSGordon Ross }
3983299f39fSGordon Ross 
3993299f39fSGordon Ross /*
4003299f39fSGordon Ross  * Read the next RPC fragment.  The xa_read() calls correspond to SmbReadX
4013299f39fSGordon Ross  * requests.  Note that there is no correspondence between SmbReadX buffering
4023299f39fSGordon Ross  * and DCE RPC fragment alignment.
4033299f39fSGordon Ross  */
4043299f39fSGordon Ross static int
ndr_clnt_get_frag(ndr_client_t * clnt,ndr_xa_t * mxa,ndr_common_header_t * hdr)4053299f39fSGordon Ross ndr_clnt_get_frag(ndr_client_t *clnt, ndr_xa_t *mxa, ndr_common_header_t *hdr)
4063299f39fSGordon Ross {
4073299f39fSGordon Ross 	ndr_stream_t		*nds = &mxa->recv_nds;
4083299f39fSGordon Ross 	unsigned long		available;
4093299f39fSGordon Ross 	int			nbytes = 0;
4103299f39fSGordon Ross 
4113299f39fSGordon Ross 	available = nds->pdu_size - nds->pdu_scan_offset;
4123299f39fSGordon Ross 
4133299f39fSGordon Ross 	while (available < NDR_RSP_HDR_SIZE) {
414*ce8560eeSMatt Barden 		if ((nbytes = (*clnt->xa_read)(clnt, mxa)) <= 0)
4153299f39fSGordon Ross 			return (-1);
4163299f39fSGordon Ross 		available += nbytes;
4173299f39fSGordon Ross 	}
4183299f39fSGordon Ross 
4193299f39fSGordon Ross 	ndr_decode_frag_hdr(nds, hdr);
4203299f39fSGordon Ross 	ndr_show_hdr(hdr);
4213299f39fSGordon Ross 
4223299f39fSGordon Ross 	while (available < hdr->frag_length) {
4233299f39fSGordon Ross 		if ((nbytes = (*clnt->xa_read)(clnt, mxa)) <= 0)
4243299f39fSGordon Ross 			return (-1);
4253299f39fSGordon Ross 		available += nbytes;
4263299f39fSGordon Ross 	}
4273299f39fSGordon Ross 
4283299f39fSGordon Ross 	return (nbytes);
4293299f39fSGordon Ross }
430