1dc20a302Sas200622 /*
2dc20a302Sas200622 * CDDL HEADER START
3dc20a302Sas200622 *
4dc20a302Sas200622 * The contents of this file are subject to the terms of the
5dc20a302Sas200622 * Common Development and Distribution License (the "License").
6dc20a302Sas200622 * You may not use this file except in compliance with the License.
7dc20a302Sas200622 *
8dc20a302Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dc20a302Sas200622 * or http://www.opensolaris.org/os/licensing.
10dc20a302Sas200622 * See the License for the specific language governing permissions
11dc20a302Sas200622 * and limitations under the License.
12dc20a302Sas200622 *
13dc20a302Sas200622 * When distributing Covered Code, include this CDDL HEADER in each
14dc20a302Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dc20a302Sas200622 * If applicable, add the following below this CDDL HEADER, with the
16dc20a302Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying
17dc20a302Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner]
18dc20a302Sas200622 *
19dc20a302Sas200622 * CDDL HEADER END
20dc20a302Sas200622 */
21dc20a302Sas200622 /*
22*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23dc20a302Sas200622 * Use is subject to license terms.
24dc20a302Sas200622 */
25dc20a302Sas200622
26dc20a302Sas200622 #include <sys/errno.h>
27dc20a302Sas200622 #include <string.h>
28dc20a302Sas200622 #include <strings.h>
29dc20a302Sas200622
30dc20a302Sas200622 #include <smbsrv/libsmb.h>
318d7e4166Sjose borrego #include <smbsrv/libmlrpc.h>
32dc20a302Sas200622
338d7e4166Sjose borrego #define NDR_DEFAULT_FRAGSZ 8192
340658b32dSAlan Wright #define NDR_MULTI_FRAGSZ (60 * 1024)
35dc20a302Sas200622
368d7e4166Sjose borrego static void ndr_clnt_init_hdr(ndr_client_t *, ndr_xa_t *);
378d7e4166Sjose borrego static int ndr_clnt_get_frags(ndr_client_t *, ndr_xa_t *);
380658b32dSAlan Wright static int ndr_clnt_get_frag(ndr_client_t *, ndr_xa_t *, ndr_common_header_t *);
39dc20a302Sas200622
40dc20a302Sas200622 int
ndr_clnt_bind(ndr_client_t * clnt,const char * service_name,ndr_binding_t ** ret_binding_p)418d7e4166Sjose borrego ndr_clnt_bind(ndr_client_t *clnt, const char *service_name,
428d7e4166Sjose borrego ndr_binding_t **ret_binding_p)
43dc20a302Sas200622 {
448d7e4166Sjose borrego ndr_service_t *msvc;
458d7e4166Sjose borrego ndr_binding_t *mbind;
468d7e4166Sjose borrego ndr_xa_t mxa;
472c1b14e5Sjose borrego ndr_bind_hdr_t *bhdr;
488d7e4166Sjose borrego ndr_p_cont_elem_t *pce;
492c1b14e5Sjose borrego ndr_bind_ack_hdr_t *bahdr;
508d7e4166Sjose borrego ndr_p_result_t *pre;
51dc20a302Sas200622 int rc;
52dc20a302Sas200622
53dc20a302Sas200622 bzero(&mxa, sizeof (mxa));
54dc20a302Sas200622
558d7e4166Sjose borrego msvc = ndr_svc_lookup_name(service_name);
56dc20a302Sas200622 if (msvc == NULL)
578d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID);
58dc20a302Sas200622
598d7e4166Sjose borrego mxa.binding_list = clnt->binding_list;
608d7e4166Sjose borrego if ((mbind = ndr_svc_new_binding(&mxa)) == NULL)
618d7e4166Sjose borrego return (NDR_DRC_FAULT_API_BIND_NO_SLOTS);
62dc20a302Sas200622
638d7e4166Sjose borrego ndr_clnt_init_hdr(clnt, &mxa);
64dc20a302Sas200622
65dc20a302Sas200622 bhdr = &mxa.send_hdr.bind_hdr;
668d7e4166Sjose borrego bhdr->common_hdr.ptype = NDR_PTYPE_BIND;
67dc20a302Sas200622 bhdr->common_hdr.frag_length = sizeof (*bhdr);
688d7e4166Sjose borrego bhdr->max_xmit_frag = NDR_DEFAULT_FRAGSZ;
698d7e4166Sjose borrego bhdr->max_recv_frag = NDR_DEFAULT_FRAGSZ;
70dc20a302Sas200622 bhdr->assoc_group_id = 0;
71dc20a302Sas200622 bhdr->p_context_elem.n_context_elem = 1;
72dc20a302Sas200622
73dc20a302Sas200622 /* Assign presentation context id */
74dc20a302Sas200622 pce = &bhdr->p_context_elem.p_cont_elem[0];
758d7e4166Sjose borrego pce->p_cont_id = clnt->next_p_cont_id++;
76dc20a302Sas200622 pce->n_transfer_syn = 1;
77dc20a302Sas200622
78dc20a302Sas200622 /* Set up UUIDs and versions from the service */
79dc20a302Sas200622 pce->abstract_syntax.if_version = msvc->abstract_syntax_version;
808d7e4166Sjose borrego rc = ndr_uuid_parse(msvc->abstract_syntax_uuid,
81dc20a302Sas200622 &pce->abstract_syntax.if_uuid);
828d7e4166Sjose borrego if (rc != 0)
838d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID);
84dc20a302Sas200622
85dc20a302Sas200622 pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version;
868d7e4166Sjose borrego rc = ndr_uuid_parse(msvc->transfer_syntax_uuid,
87dc20a302Sas200622 &pce->transfer_syntaxes[0].if_uuid);
888d7e4166Sjose borrego if (rc != 0)
898d7e4166Sjose borrego return (NDR_DRC_FAULT_API_SERVICE_INVALID);
90dc20a302Sas200622
91dc20a302Sas200622 /* Format and exchange the PDU */
92dc20a302Sas200622
938d7e4166Sjose borrego if ((*clnt->xa_init)(clnt, &mxa) < 0)
948d7e4166Sjose borrego return (NDR_DRC_FAULT_OUT_OF_MEMORY);
95dc20a302Sas200622
968d7e4166Sjose borrego rc = ndr_encode_pdu_hdr(&mxa);
978d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
98dc20a302Sas200622 goto fault_exit;
99dc20a302Sas200622
1008d7e4166Sjose borrego if ((*clnt->xa_exchange)(clnt, &mxa) < 0) {
1018d7e4166Sjose borrego rc = NDR_DRC_FAULT_SEND_FAILED;
102dc20a302Sas200622 goto fault_exit;
1038d7e4166Sjose borrego }
104dc20a302Sas200622
1058d7e4166Sjose borrego rc = ndr_decode_pdu_hdr(&mxa);
1068d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
107dc20a302Sas200622 goto fault_exit;
108dc20a302Sas200622
109dc20a302Sas200622 /* done with buffers */
1108d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa);
111dc20a302Sas200622
112dc20a302Sas200622 bahdr = &mxa.recv_hdr.bind_ack_hdr;
113dc20a302Sas200622
1148d7e4166Sjose borrego if (mxa.ptype != NDR_PTYPE_BIND_ACK)
1158d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
116dc20a302Sas200622
117dc20a302Sas200622 if (bahdr->p_result_list.n_results != 1)
1188d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
119dc20a302Sas200622
120dc20a302Sas200622 pre = &bahdr->p_result_list.p_results[0];
121dc20a302Sas200622
1228d7e4166Sjose borrego if (pre->result != NDR_PCDR_ACCEPTANCE)
1238d7e4166Sjose borrego return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
124dc20a302Sas200622
125dc20a302Sas200622 mbind->p_cont_id = pce->p_cont_id;
1268d7e4166Sjose borrego mbind->which_side = NDR_BIND_SIDE_CLIENT;
1278d7e4166Sjose borrego mbind->clnt = clnt;
128dc20a302Sas200622 mbind->service = msvc;
129dc20a302Sas200622 mbind->instance_specific = 0;
130dc20a302Sas200622
131dc20a302Sas200622 *ret_binding_p = mbind;
1328d7e4166Sjose borrego return (NDR_DRC_OK);
133dc20a302Sas200622
134dc20a302Sas200622 fault_exit:
1358d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa);
136dc20a302Sas200622 return (rc);
137dc20a302Sas200622 }
138dc20a302Sas200622
139dc20a302Sas200622 int
ndr_clnt_call(ndr_binding_t * mbind,int opnum,void * params)1408d7e4166Sjose borrego ndr_clnt_call(ndr_binding_t *mbind, int opnum, void *params)
141dc20a302Sas200622 {
1428d7e4166Sjose borrego ndr_client_t *clnt = mbind->clnt;
1438d7e4166Sjose borrego ndr_service_t *msvc = mbind->service;
1448d7e4166Sjose borrego ndr_xa_t mxa;
1452c1b14e5Sjose borrego ndr_request_hdr_t *reqhdr;
1462c1b14e5Sjose borrego ndr_common_header_t *rsphdr;
147dc20a302Sas200622 unsigned long recv_pdu_scan_offset;
148dc20a302Sas200622 int rc;
149dc20a302Sas200622
150b1352070SAlan Wright if (ndr_svc_lookup_name(msvc->name) == NULL)
151b1352070SAlan Wright return (NDR_DRC_FAULT_API_SERVICE_INVALID);
152dc20a302Sas200622
153dc20a302Sas200622 bzero(&mxa, sizeof (mxa));
1548d7e4166Sjose borrego mxa.ptype = NDR_PTYPE_REQUEST;
155dc20a302Sas200622 mxa.opnum = opnum;
156dc20a302Sas200622 mxa.binding = mbind;
157dc20a302Sas200622
1588d7e4166Sjose borrego ndr_clnt_init_hdr(clnt, &mxa);
159dc20a302Sas200622
160dc20a302Sas200622 reqhdr = &mxa.send_hdr.request_hdr;
1618d7e4166Sjose borrego reqhdr->common_hdr.ptype = NDR_PTYPE_REQUEST;
162dc20a302Sas200622 reqhdr->p_cont_id = mbind->p_cont_id;
163dc20a302Sas200622 reqhdr->opnum = opnum;
164dc20a302Sas200622
1658d7e4166Sjose borrego rc = (*clnt->xa_init)(clnt, &mxa);
1668d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
167dc20a302Sas200622 return (rc);
168dc20a302Sas200622
169dc20a302Sas200622 /* Reserve room for hdr */
1708d7e4166Sjose borrego mxa.send_nds.pdu_scan_offset = sizeof (*reqhdr);
171dc20a302Sas200622
1728d7e4166Sjose borrego rc = ndr_encode_call(&mxa, params);
1738d7e4166Sjose borrego if (!NDR_DRC_IS_OK(rc))
174dc20a302Sas200622 goto fault_exit;
175dc20a302Sas200622
1768d7e4166Sjose borrego mxa.send_nds.pdu_scan_offset = 0;
177dc20a302Sas200622
178dc20a302Sas200622 /*
179dc20a302Sas200622 * Now we have the PDU size, we need to set up the
180dc20a302Sas200622 * frag_length and calculate the alloc_hint.
181dc20a302Sas200622 */
1828d7e4166Sjose borrego mxa.send_hdr.common_hdr.frag_length = mxa.send_nds.pdu_size;
1838d7e4166Sjose borrego reqhdr->alloc_hint = mxa.send_nds.pdu_size -
1842c1b14e5Sjose borrego sizeof (ndr_request_hdr_t);
185dc20a302Sas200622
1868d7e4166Sjose borrego rc = ndr_encode_pdu_hdr(&mxa);
1878d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
188dc20a302Sas200622 goto fault_exit;
189dc20a302Sas200622
1908d7e4166Sjose borrego rc = (*clnt->xa_exchange)(clnt, &mxa);
1918d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
192dc20a302Sas200622 goto fault_exit;
193dc20a302Sas200622
1948d7e4166Sjose borrego rc = ndr_decode_pdu_hdr(&mxa);
1958d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
196dc20a302Sas200622 goto fault_exit;
197dc20a302Sas200622
1988d7e4166Sjose borrego if (mxa.ptype != NDR_PTYPE_RESPONSE) {
1998d7e4166Sjose borrego rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
200dc20a302Sas200622 goto fault_exit;
201dc20a302Sas200622 }
202dc20a302Sas200622
203dc20a302Sas200622 rsphdr = &mxa.recv_hdr.common_hdr;
204dc20a302Sas200622
2058d7e4166Sjose borrego if (!NDR_IS_LAST_FRAG(rsphdr->pfc_flags)) {
206dc20a302Sas200622 /*
207dc20a302Sas200622 * This is a multi-fragment response.
208dc20a302Sas200622 * Preserve the current scan offset while getting
209dc20a302Sas200622 * fragments so that we can continue afterward
210dc20a302Sas200622 * as if we had received the entire response as
211dc20a302Sas200622 * a single PDU.
212dc20a302Sas200622 */
2130658b32dSAlan Wright (void) NDS_GROW_PDU(&mxa.recv_nds, NDR_MULTI_FRAGSZ, NULL);
2140658b32dSAlan Wright
2158d7e4166Sjose borrego recv_pdu_scan_offset = mxa.recv_nds.pdu_scan_offset;
2160658b32dSAlan Wright mxa.recv_nds.pdu_scan_offset = rsphdr->frag_length;
2170658b32dSAlan Wright mxa.recv_nds.pdu_size = rsphdr->frag_length;
218dc20a302Sas200622
2198d7e4166Sjose borrego if (ndr_clnt_get_frags(clnt, &mxa) < 0) {
2208d7e4166Sjose borrego rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
221dc20a302Sas200622 goto fault_exit;
222dc20a302Sas200622 }
223dc20a302Sas200622
2248d7e4166Sjose borrego mxa.recv_nds.pdu_scan_offset = recv_pdu_scan_offset;
225dc20a302Sas200622 }
226dc20a302Sas200622
2278d7e4166Sjose borrego rc = ndr_decode_return(&mxa, params);
2288d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc))
229dc20a302Sas200622 goto fault_exit;
230dc20a302Sas200622
2318d7e4166Sjose borrego (*clnt->xa_preserve)(clnt, &mxa);
2328d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa);
2338d7e4166Sjose borrego return (NDR_DRC_OK);
234dc20a302Sas200622
235dc20a302Sas200622 fault_exit:
2368d7e4166Sjose borrego (*clnt->xa_destruct)(clnt, &mxa);
237dc20a302Sas200622 return (rc);
238dc20a302Sas200622 }
239dc20a302Sas200622
240dc20a302Sas200622 void
ndr_clnt_free_heap(ndr_client_t * clnt)2418d7e4166Sjose borrego ndr_clnt_free_heap(ndr_client_t *clnt)
242dc20a302Sas200622 {
2438d7e4166Sjose borrego (*clnt->xa_release)(clnt);
244dc20a302Sas200622 }
245dc20a302Sas200622
246dc20a302Sas200622 static void
ndr_clnt_init_hdr(ndr_client_t * clnt,ndr_xa_t * mxa)2478d7e4166Sjose borrego ndr_clnt_init_hdr(ndr_client_t *clnt, ndr_xa_t *mxa)
248dc20a302Sas200622 {
2492c1b14e5Sjose borrego ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
250dc20a302Sas200622
251dc20a302Sas200622 hdr->rpc_vers = 5;
252dc20a302Sas200622 hdr->rpc_vers_minor = 0;
2538d7e4166Sjose borrego hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
2548d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII;
255dc20a302Sas200622 #ifndef _BIG_ENDIAN
2568d7e4166Sjose borrego hdr->packed_drep.intg_char_rep |= NDR_REPLAB_INTG_LITTLE_ENDIAN;
257dc20a302Sas200622 #endif
258dc20a302Sas200622 /* hdr->frag_length */
259dc20a302Sas200622 hdr->auth_length = 0;
2608d7e4166Sjose borrego hdr->call_id = clnt->next_call_id++;
261dc20a302Sas200622 }
262dc20a302Sas200622
263dc20a302Sas200622 /*
2648d7e4166Sjose borrego * ndr_clnt_get_frags
265dc20a302Sas200622 *
266dc20a302Sas200622 * A DCE RPC message that is larger than a single fragment is transmitted
267dc20a302Sas200622 * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for
268dc20a302Sas200622 * both Windows 2000 and 2003.
269dc20a302Sas200622 *
270dc20a302Sas200622 * Collect RPC fragments and append them to the receive stream buffer.
271dc20a302Sas200622 * Each received fragment has a header, which we need to remove as we
2720658b32dSAlan Wright * build the full RPC PDU. The scan offset is used to track frag headers.
273dc20a302Sas200622 */
274dc20a302Sas200622 static int
ndr_clnt_get_frags(ndr_client_t * clnt,ndr_xa_t * mxa)2758d7e4166Sjose borrego ndr_clnt_get_frags(ndr_client_t *clnt, ndr_xa_t *mxa)
276dc20a302Sas200622 {
2778d7e4166Sjose borrego ndr_stream_t *nds = &mxa->recv_nds;
2782c1b14e5Sjose borrego ndr_common_header_t hdr;
279dc20a302Sas200622 int frag_size;
280dc20a302Sas200622 int last_frag;
281dc20a302Sas200622
282dc20a302Sas200622 do {
2830658b32dSAlan Wright if (ndr_clnt_get_frag(clnt, mxa, &hdr) < 0) {
2840658b32dSAlan Wright nds_show_state(nds);
285dc20a302Sas200622 return (-1);
286dc20a302Sas200622 }
287dc20a302Sas200622
2880658b32dSAlan Wright last_frag = NDR_IS_LAST_FRAG(hdr.pfc_flags);
2890658b32dSAlan Wright frag_size = hdr.frag_length;
290dc20a302Sas200622
2910658b32dSAlan Wright if (frag_size > (nds->pdu_size - nds->pdu_scan_offset)) {
2920658b32dSAlan Wright nds_show_state(nds);
2930658b32dSAlan Wright return (-1);
2940658b32dSAlan Wright }
2950658b32dSAlan Wright
296*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ndr_remove_frag_hdr(nds);
2970658b32dSAlan Wright nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
298dc20a302Sas200622 } while (!last_frag);
299dc20a302Sas200622
300dc20a302Sas200622 return (0);
301dc20a302Sas200622 }
3020658b32dSAlan Wright
3030658b32dSAlan Wright /*
3040658b32dSAlan Wright * Read the next RPC fragment. The xa_read() calls correspond to SmbReadX
3050658b32dSAlan Wright * requests. Note that there is no correspondence between SmbReadX buffering
3060658b32dSAlan Wright * and DCE RPC fragment alignment.
3070658b32dSAlan Wright */
3080658b32dSAlan Wright static int
ndr_clnt_get_frag(ndr_client_t * clnt,ndr_xa_t * mxa,ndr_common_header_t * hdr)3090658b32dSAlan Wright ndr_clnt_get_frag(ndr_client_t *clnt, ndr_xa_t *mxa, ndr_common_header_t *hdr)
3100658b32dSAlan Wright {
3110658b32dSAlan Wright ndr_stream_t *nds = &mxa->recv_nds;
3120658b32dSAlan Wright unsigned long available;
3130658b32dSAlan Wright int nbytes = 0;
3140658b32dSAlan Wright
3150658b32dSAlan Wright available = nds->pdu_size - nds->pdu_scan_offset;
3160658b32dSAlan Wright
3170658b32dSAlan Wright while (available < NDR_RSP_HDR_SIZE) {
3180658b32dSAlan Wright if ((nbytes += (*clnt->xa_read)(clnt, mxa)) <= 0)
3190658b32dSAlan Wright return (-1);
3200658b32dSAlan Wright available += nbytes;
3210658b32dSAlan Wright }
3220658b32dSAlan Wright
3230658b32dSAlan Wright ndr_decode_frag_hdr(nds, hdr);
3240658b32dSAlan Wright ndr_show_hdr(hdr);
3250658b32dSAlan Wright
3260658b32dSAlan Wright while (available < hdr->frag_length) {
3270658b32dSAlan Wright if ((nbytes = (*clnt->xa_read)(clnt, mxa)) <= 0)
3280658b32dSAlan Wright return (-1);
3290658b32dSAlan Wright available += nbytes;
3300658b32dSAlan Wright }
3310658b32dSAlan Wright
3320658b32dSAlan Wright return (nbytes);
3330658b32dSAlan Wright }
334