xref: /titanic_50/usr/src/lib/smbsrv/libmlrpc/common/ndr_client.c (revision 9fb67ea305c66b6a297583b9b0db6796b0dfe497)
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