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