ndr_marshal.c revision 7619:0ad244464731
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <strings.h>
27#include <sys/param.h>
28
29#include <smbsrv/libsmb.h>
30#include <smbsrv/ndr.h>
31#include <smbsrv/mlrpc.h>
32
33#ifdef _BIG_ENDIAN
34static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_BIG_ENDIAN;
35#else
36static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
37#endif
38
39int
40mlrpc_encode_decode_common(struct mlrpc_xaction *mxa, int mode, unsigned opnum,
41    struct ndr_typeinfo *ti, void *datum)
42{
43	struct mlndr_stream	*mlnds;
44	int			m_op = NDR_MODE_TO_M_OP(mode);
45	int			rc;
46
47	if (m_op == NDR_M_OP_MARSHALL)
48		mlnds = &mxa->send_mlnds;
49	else
50		mlnds = &mxa->recv_mlnds;
51
52	/*
53	 * Make sure that mlnds is in the correct mode
54	 */
55	if (!NDR_MODE_MATCH(mlnds, mode))
56		return (MLRPC_DRC_FAULT_MODE_MISMATCH);
57
58	/*
59	 * Perform the (un)marshalling
60	 */
61	if (mlndo_operation(mlnds, ti, opnum, datum))
62		return (MLRPC_DRC_OK);
63
64	switch (mlnds->error) {
65	case NDR_ERR_MALLOC_FAILED:
66		rc = MLRPC_DRC_FAULT_OUT_OF_MEMORY;
67		break;
68
69	case NDR_ERR_SWITCH_VALUE_INVALID:
70		rc = MLRPC_DRC_FAULT_PARAM_0_INVALID;
71		break;
72
73	case NDR_ERR_UNDERFLOW:
74		rc = MLRPC_DRC_FAULT_RECEIVED_RUNT;
75		break;
76
77	case NDR_ERR_GROW_FAILED:
78		rc = MLRPC_DRC_FAULT_ENCODE_TOO_BIG;
79		break;
80
81	default:
82		if (m_op == NDR_M_OP_MARSHALL)
83			rc = MLRPC_DRC_FAULT_ENCODE_FAILED;
84		else
85			rc = MLRPC_DRC_FAULT_DECODE_FAILED;
86		break;
87	}
88
89	return (rc);
90}
91
92int
93mlrpc_decode_call(struct mlrpc_xaction *mxa, void *params)
94{
95	int rc;
96
97	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_RECV,
98	    mxa->opnum, mxa->binding->service->interface_ti, params);
99
100	return (rc + MLRPC_PTYPE_REQUEST);
101}
102
103int
104mlrpc_encode_return(struct mlrpc_xaction *mxa, void *params)
105{
106	int rc;
107
108	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_SEND,
109	    mxa->opnum, mxa->binding->service->interface_ti, params);
110
111	return (rc + MLRPC_PTYPE_RESPONSE);
112}
113
114int
115mlrpc_encode_call(struct mlrpc_xaction *mxa, void *params)
116{
117	int rc;
118
119	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_SEND,
120	    mxa->opnum, mxa->binding->service->interface_ti, params);
121
122	return (rc + MLRPC_PTYPE_REQUEST);
123}
124
125int
126mlrpc_decode_return(struct mlrpc_xaction *mxa, void *params)
127{
128	int rc;
129
130	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_RECV,
131	    mxa->opnum, mxa->binding->service->interface_ti, params);
132
133	return (rc + MLRPC_PTYPE_RESPONSE);
134}
135
136int
137mlrpc_decode_pdu_hdr(struct mlrpc_xaction *mxa)
138{
139	ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
140	struct mlndr_stream 	*mlnds = &mxa->recv_mlnds;
141	int			ptype;
142	int			rc;
143	int			charset;
144	int			byte_order;
145
146	if (mlnds->m_op != NDR_M_OP_UNMARSHALL)
147		return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
148
149	/*
150	 * All PDU headers are at least this big
151	 */
152	rc = MLNDS_GROW_PDU(mlnds, sizeof (ndr_common_header_t), 0);
153	if (!rc)
154		return (MLRPC_DRC_FAULT_RECEIVED_RUNT + 0xFF);
155
156	/*
157	 * Peek at the first eight bytes to figure out what we're doing.
158	 */
159	rc = MLNDS_GET_PDU(mlnds, 0, 8, (char *)hdr, 0, 0);
160	if (!rc)
161		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
162
163	/*
164	 * Verify the protocol version.
165	 */
166	if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0))
167		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
168
169	/*
170	 * Check for ASCII as the character set.  This is an ASCII
171	 * versus EBCDIC option and has nothing to do with Unicode.
172	 */
173	charset = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_CHAR_MASK;
174	if (charset != MLRPC_REPLAB_CHAR_ASCII)
175		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
176
177	/*
178	 * Set the byte swap flag if the PDU byte-order
179	 * is different from the local byte-order.
180	 */
181	byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
182	mlnds->swap = (byte_order != mlrpc_native_byte_order) ? 1 : 0;
183
184	ptype = hdr->ptype;
185	if (ptype == MLRPC_PTYPE_REQUEST &&
186	    (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
187		ptype = MLRPC_PTYPE_REQUEST_WITH;	/* fake for sizing */
188	}
189
190	mxa->ptype = hdr->ptype;
191
192	rc = mlrpc_encode_decode_common(mxa,
193	    NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
194	    ptype, &TYPEINFO(ndr_hdr), hdr);
195
196	return (rc + 0xFF);
197}
198
199/*
200 * Decode an RPC fragment header.  Use mlrpc_decode_pdu_hdr() to process
201 * the first fragment header then this function to process additional
202 * fragment headers.
203 */
204void
205mlrpc_decode_frag_hdr(struct mlndr_stream *mlnds, ndr_common_header_t *hdr)
206{
207	ndr_common_header_t *tmp;
208	uint8_t *pdu;
209	int byte_order;
210
211	pdu = (uint8_t *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset;
212	bcopy(pdu, hdr, MLRPC_RSP_HDR_SIZE);
213
214	/*
215	 * Swap non-byte fields if the PDU byte-order
216	 * is different from the local byte-order.
217	 */
218	byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
219
220	if (byte_order != mlrpc_native_byte_order) {
221		/*LINTED E_BAD_PTR_CAST_ALIGN*/
222		tmp = (ndr_common_header_t *)pdu;
223
224		mlnds_bswap(&tmp->frag_length, &hdr->frag_length,
225		    sizeof (WORD));
226		mlnds_bswap(&tmp->auth_length, &hdr->auth_length,
227		    sizeof (WORD));
228		mlnds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD));
229	}
230}
231
232int
233mlrpc_encode_pdu_hdr(struct mlrpc_xaction *mxa)
234{
235	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
236	struct mlndr_stream 	*mlnds = &mxa->send_mlnds;
237	int			ptype;
238	int			rc;
239
240	if (mlnds->m_op != NDR_M_OP_MARSHALL)
241		return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
242
243	ptype = hdr->ptype;
244	if (ptype == MLRPC_PTYPE_REQUEST &&
245	    (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
246		ptype = MLRPC_PTYPE_REQUEST_WITH;	/* fake for sizing */
247	}
248
249	rc = mlrpc_encode_decode_common(mxa,
250	    NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
251	    ptype, &TYPEINFO(ndr_hdr), hdr);
252
253	return (rc + 0xFF);
254}
255
256/*
257 * This is a hand-coded derivative of the automatically generated
258 * (un)marshalling routine for bind_ack headers. bind_ack headers
259 * have an interior conformant array, which is inconsistent with
260 * IDL/NDR rules.
261 */
262extern struct ndr_typeinfo ndt__uchar;
263extern struct ndr_typeinfo ndt__ushort;
264extern struct ndr_typeinfo ndt__ulong;
265
266int mlndr__ndr_bind_ack_hdr(struct ndr_reference *encl_ref);
267struct ndr_typeinfo ndt__ndr_bind_ack_hdr = {
268    1,		/* NDR version */
269    3,		/* alignment */
270    NDR_F_STRUCT,	/* flags */
271    mlndr__ndr_bind_ack_hdr,	/* ndr_func */
272    68,		/* pdu_size_fixed_part */
273    0,		/* pdu_size_variable_part */
274    68,		/* c_size_fixed_part */
275    0,		/* c_size_variable_part */
276};
277
278/*
279 * [_no_reorder]
280 */
281int
282mlndr__ndr_bind_ack_hdr(struct ndr_reference *encl_ref)
283{
284	struct mlndr_stream 	*mlnds = encl_ref->stream;
285	struct ndr_bind_ack_hdr	*val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
286	    (struct ndr_bind_ack_hdr *)encl_ref->datum;
287	struct ndr_reference	myref;
288	unsigned long		offset;
289
290	bzero(&myref, sizeof (myref));
291	myref.enclosing = encl_ref;
292	myref.stream = encl_ref->stream;
293	myref.packed_alignment = 0;
294
295	/* do all members in order */
296	NDR_MEMBER(_ndr_common_header, common_hdr, 0UL);
297	NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
298	NDR_MEMBER(_ushort, max_recv_frag, 18UL);
299	NDR_MEMBER(_ulong, assoc_group_id, 20UL);
300
301	/* port any is the conformant culprit */
302	offset = 24UL;
303
304	switch (mlnds->m_op) {
305	case NDR_M_OP_MARSHALL:
306		val->sec_addr.length =
307		    strlen((char *)val->sec_addr.port_spec) + 1;
308		break;
309
310	case NDR_M_OP_UNMARSHALL:
311		break;
312
313	default:
314		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
315		return (0);
316	}
317
318	NDR_MEMBER(_ushort, sec_addr.length, offset);
319	NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
320	    offset+2UL, val->sec_addr.length);
321
322	offset += 2;
323	offset += val->sec_addr.length;
324	offset += (4 - offset) & 3;
325
326	NDR_MEMBER(_mlrpc_p_result_list, p_result_list, offset);
327	return (1);
328}
329
330/*
331 * Assume a single presentation context element in the result list.
332 */
333unsigned
334mlrpc_bind_ack_hdr_size(struct mlrpc_xaction *mxa)
335{
336	ndr_bind_ack_hdr_t *bahdr = &mxa->send_hdr.bind_ack_hdr;
337	unsigned	offset;
338	unsigned	length;
339
340	/* port any is the conformant culprit */
341	offset = 24UL;
342
343	length = strlen((char *)bahdr->sec_addr.port_spec) + 1;
344
345	offset += 2;
346	offset += length;
347	offset += (4 - offset) & 3;
348	offset += sizeof (mlrpc_p_result_list_t);
349	return (offset);
350}
351
352/*
353 * This is a hand-coded derivative of the automatically generated
354 * (un)marshalling routine for alter_context_rsp headers.
355 * Alter context response headers have an interior conformant array,
356 * which is inconsistent with IDL/NDR rules.
357 */
358int mlndr__ndr_alter_context_rsp_hdr(struct ndr_reference *encl_ref);
359struct ndr_typeinfo ndt__ndr_alter_context_rsp_hdr = {
360    1,			/* NDR version */
361    3,			/* alignment */
362    NDR_F_STRUCT,	/* flags */
363    mlndr__ndr_alter_context_rsp_hdr,	/* ndr_func */
364    56,			/* pdu_size_fixed_part */
365    0,			/* pdu_size_variable_part */
366    56,			/* c_size_fixed_part */
367    0,			/* c_size_variable_part */
368};
369
370/*
371 * [_no_reorder]
372 */
373int
374mlndr__ndr_alter_context_rsp_hdr(struct ndr_reference *encl_ref)
375{
376	struct mlndr_stream 	*mlnds = encl_ref->stream;
377	ndr_alter_context_rsp_hdr_t *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
378	    (ndr_alter_context_rsp_hdr_t *)encl_ref->datum;
379	struct ndr_reference	myref;
380	unsigned long		offset;
381
382	bzero(&myref, sizeof (myref));
383	myref.enclosing = encl_ref;
384	myref.stream = encl_ref->stream;
385	myref.packed_alignment = 0;
386
387	/* do all members in order */
388	NDR_MEMBER(_ndr_common_header, common_hdr, 0UL);
389	NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
390	NDR_MEMBER(_ushort, max_recv_frag, 18UL);
391	NDR_MEMBER(_ulong, assoc_group_id, 20UL);
392
393	offset = 24UL;	/* offset of sec_addr */
394
395	switch (mlnds->m_op) {
396	case NDR_M_OP_MARSHALL:
397		val->sec_addr.length = 0;
398		break;
399
400	case NDR_M_OP_UNMARSHALL:
401		break;
402
403	default:
404		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
405		return (0);
406	}
407
408	NDR_MEMBER(_ushort, sec_addr.length, offset);
409	NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
410	    offset+2UL, val->sec_addr.length);
411
412	offset += 2;	/* sizeof (sec_addr.length) */
413	offset += (4 - offset) & 3;
414
415	NDR_MEMBER(_mlrpc_p_result_list, p_result_list, offset);
416	return (1);
417}
418
419/*
420 * Assume a single presentation context element in the result list.
421 */
422unsigned
423mlrpc_alter_context_rsp_hdr_size(void)
424{
425	unsigned	offset;
426
427	offset = 24UL;	/* offset of sec_addr */
428	offset += 2;	/* sizeof (sec_addr.length) */
429	offset += (4 - offset) & 3;
430	offset += sizeof (mlrpc_p_result_list_t);
431	return (offset);
432}
433