xref: /titanic_50/usr/src/lib/smbsrv/libmlrpc/common/ndr_marshal.c (revision ff17c8bf86c3e567734be83f90267edee20f580f)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <strings.h>
29 #include <sys/param.h>
30 
31 #include <smbsrv/libsmb.h>
32 #include <smbsrv/ndr.h>
33 #include <smbsrv/mlrpc.h>
34 
35 #ifdef _BIG_ENDIAN
36 static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_BIG_ENDIAN;
37 #else
38 static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
39 #endif
40 
41 int
42 mlrpc_encode_decode_common(struct mlrpc_xaction *mxa, int mode, unsigned opnum,
43     struct ndr_typeinfo *ti, void *datum)
44 {
45 	struct mlndr_stream	*mlnds;
46 	int			m_op = NDR_MODE_TO_M_OP(mode);
47 	int			rc;
48 
49 	if (m_op == NDR_M_OP_MARSHALL)
50 		mlnds = &mxa->send_mlnds;
51 	else
52 		mlnds = &mxa->recv_mlnds;
53 
54 	/*
55 	 * Make sure that mlnds is in the correct mode
56 	 */
57 	if (!NDR_MODE_MATCH(mlnds, mode))
58 		return (MLRPC_DRC_FAULT_MODE_MISMATCH);
59 
60 	/*
61 	 * Perform the (un)marshalling
62 	 */
63 	if (mlndo_operation(mlnds, ti, opnum, datum))
64 		return (MLRPC_DRC_OK);
65 
66 	switch (mlnds->error) {
67 	case NDR_ERR_MALLOC_FAILED:
68 		rc = MLRPC_DRC_FAULT_OUT_OF_MEMORY;
69 		break;
70 
71 	case NDR_ERR_SWITCH_VALUE_INVALID:
72 		rc = MLRPC_DRC_FAULT_PARAM_0_INVALID;
73 		break;
74 
75 	case NDR_ERR_UNDERFLOW:
76 		rc = MLRPC_DRC_FAULT_RECEIVED_RUNT;
77 		break;
78 
79 	case NDR_ERR_GROW_FAILED:
80 		rc = MLRPC_DRC_FAULT_ENCODE_TOO_BIG;
81 		break;
82 
83 	default:
84 		if (m_op == NDR_M_OP_MARSHALL)
85 			rc = MLRPC_DRC_FAULT_ENCODE_FAILED;
86 		else
87 			rc = MLRPC_DRC_FAULT_DECODE_FAILED;
88 		break;
89 	}
90 
91 	return (rc);
92 }
93 
94 int
95 mlrpc_decode_call(struct mlrpc_xaction *mxa, void *params)
96 {
97 	int rc;
98 
99 	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_RECV,
100 	    mxa->opnum, mxa->binding->service->interface_ti, params);
101 
102 	return (rc + MLRPC_PTYPE_REQUEST);
103 }
104 
105 int
106 mlrpc_encode_return(struct mlrpc_xaction *mxa, void *params)
107 {
108 	int rc;
109 
110 	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_SEND,
111 	    mxa->opnum, mxa->binding->service->interface_ti, params);
112 
113 	return (rc + MLRPC_PTYPE_RESPONSE);
114 }
115 
116 int
117 mlrpc_encode_call(struct mlrpc_xaction *mxa, void *params)
118 {
119 	int rc;
120 
121 	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_SEND,
122 	    mxa->opnum, mxa->binding->service->interface_ti, params);
123 
124 	return (rc + MLRPC_PTYPE_REQUEST);
125 }
126 
127 int
128 mlrpc_decode_return(struct mlrpc_xaction *mxa, void *params)
129 {
130 	int rc;
131 
132 	rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_RECV,
133 	    mxa->opnum, mxa->binding->service->interface_ti, params);
134 
135 	return (rc + MLRPC_PTYPE_RESPONSE);
136 }
137 
138 int
139 mlrpc_decode_pdu_hdr(struct mlrpc_xaction *mxa)
140 {
141 	mlrpcconn_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
142 	struct mlndr_stream 	*mlnds = &mxa->recv_mlnds;
143 	int			ptype;
144 	int			rc;
145 	int			charset;
146 	int			byte_order;
147 
148 	if (mlnds->m_op != NDR_M_OP_UNMARSHALL)
149 		return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
150 
151 	/*
152 	 * All PDU headers are at least this big
153 	 */
154 	rc = MLNDS_GROW_PDU(mlnds, sizeof (mlrpcconn_common_header_t), 0);
155 	if (!rc)
156 		return (MLRPC_DRC_FAULT_RECEIVED_RUNT + 0xFF);
157 
158 	/*
159 	 * Peek at the first eight bytes to figure out what we're doing.
160 	 */
161 	rc = MLNDS_GET_PDU(mlnds, 0, 8, (char *)hdr, 0, 0);
162 	if (!rc)
163 		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
164 
165 	/*
166 	 * Verify the protocol version.
167 	 */
168 	if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0))
169 		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
170 
171 	/*
172 	 * Check for ASCII as the character set.  This is an ASCII
173 	 * versus EBCDIC option and has nothing to do with Unicode.
174 	 */
175 	charset = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_CHAR_MASK;
176 	if (charset != MLRPC_REPLAB_CHAR_ASCII)
177 		return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF);
178 
179 	/*
180 	 * Set the byte swap flag if the PDU byte-order
181 	 * is different from the local byte-order.
182 	 */
183 	byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
184 	mlnds->swap = (byte_order != mlrpc_native_byte_order) ? 1 : 0;
185 
186 	ptype = hdr->ptype;
187 	if (ptype == MLRPC_PTYPE_REQUEST &&
188 	    (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
189 		ptype = MLRPC_PTYPE_REQUEST_WITH;	/* fake for sizing */
190 	}
191 
192 	mxa->ptype = hdr->ptype;
193 
194 	rc = mlrpc_encode_decode_common(mxa,
195 	    NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
196 	    ptype, &TYPEINFO(mlrpcconn_hdr), hdr);
197 
198 	return (rc + 0xFF);
199 }
200 
201 /*
202  * Decode an RPC fragment header.  Use mlrpc_decode_pdu_hdr() to process
203  * the first fragment header then this function to process additional
204  * fragment headers.
205  */
206 void
207 mlrpc_decode_frag_hdr(struct mlndr_stream *mlnds,
208     mlrpcconn_common_header_t *hdr)
209 {
210 	mlrpcconn_common_header_t *tmp;
211 	uint8_t *pdu;
212 	int byte_order;
213 
214 	pdu = (uint8_t *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset;
215 	bcopy(pdu, hdr, MLRPC_RSP_HDR_SIZE);
216 
217 	/*
218 	 * Swap non-byte fields if the PDU byte-order
219 	 * is different from the local byte-order.
220 	 */
221 	byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK;
222 
223 	if (byte_order != mlrpc_native_byte_order) {
224 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
225 		tmp = (mlrpcconn_common_header_t *)pdu;
226 
227 		mlnds_bswap(&tmp->frag_length, &hdr->frag_length,
228 		    sizeof (WORD));
229 		mlnds_bswap(&tmp->auth_length, &hdr->auth_length,
230 		    sizeof (WORD));
231 		mlnds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD));
232 	}
233 }
234 
235 int
236 mlrpc_encode_pdu_hdr(struct mlrpc_xaction *mxa)
237 {
238 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
239 	struct mlndr_stream 	*mlnds = &mxa->send_mlnds;
240 	int			ptype;
241 	int			rc;
242 
243 	if (mlnds->m_op != NDR_M_OP_MARSHALL)
244 		return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF);
245 
246 	ptype = hdr->ptype;
247 	if (ptype == MLRPC_PTYPE_REQUEST &&
248 	    (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) {
249 		ptype = MLRPC_PTYPE_REQUEST_WITH;	/* fake for sizing */
250 	}
251 
252 	rc = mlrpc_encode_decode_common(mxa,
253 	    NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir),
254 	    ptype, &TYPEINFO(mlrpcconn_hdr), hdr);
255 
256 	return (rc + 0xFF);
257 }
258 
259 /*
260  * This is a hand-coded derivative of the automatically generated
261  * (un)marshalling routine for bind_ack headers. bind_ack headers
262  * have an interior conformant array, which is inconsistent with
263  * IDL/NDR rules.
264  */
265 extern struct ndr_typeinfo ndt__uchar;
266 extern struct ndr_typeinfo ndt__ushort;
267 extern struct ndr_typeinfo ndt__ulong;
268 
269 int mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref);
270 struct ndr_typeinfo ndt__mlrpcconn_bind_ack_hdr = {
271     1,		/* NDR version */
272     3,		/* alignment */
273     NDR_F_STRUCT,	/* flags */
274     mlndr__mlrpcconn_bind_ack_hdr,	/* ndr_func */
275     68,		/* pdu_size_fixed_part */
276     0,		/* pdu_size_variable_part */
277     68,		/* c_size_fixed_part */
278     0,		/* c_size_variable_part */
279 };
280 
281 /*
282  * [_no_reorder]
283  */
284 int
285 mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref)
286 {
287 	struct mlndr_stream 		*mlnds = encl_ref->stream;
288 	struct mlrpcconn_bind_ack_hdr   *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
289 	    (struct mlrpcconn_bind_ack_hdr *)encl_ref->datum;
290 	struct ndr_reference	myref;
291 	unsigned long		offset;
292 
293 	bzero(&myref, sizeof (myref));
294 	myref.enclosing = encl_ref;
295 	myref.stream = encl_ref->stream;
296 	myref.packed_alignment = 0;
297 
298 	/* do all members in order */
299 	NDR_MEMBER(_mlrpcconn_common_header, common_hdr, 0UL);
300 	NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
301 	NDR_MEMBER(_ushort, max_recv_frag, 18UL);
302 	NDR_MEMBER(_ulong, assoc_group_id, 20UL);
303 
304 	/* port any is the conformant culprit */
305 	offset = 24UL;
306 
307 	switch (mlnds->m_op) {
308 	case NDR_M_OP_MARSHALL:
309 		val->sec_addr.length =
310 		    strlen((char *)val->sec_addr.port_spec) + 1;
311 		break;
312 
313 	case NDR_M_OP_UNMARSHALL:
314 		break;
315 
316 	default:
317 		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
318 		return (0);
319 	}
320 
321 	NDR_MEMBER(_ushort, sec_addr.length, offset);
322 	NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
323 	    offset+2UL, val->sec_addr.length);
324 
325 	offset += 2;
326 	offset += val->sec_addr.length;
327 	offset += (4 - offset) & 3;
328 
329 	NDR_MEMBER(_mlrpc_p_result_list, p_result_list, offset);
330 	return (1);
331 }
332 
333 unsigned
334 mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *bahdr)
335 {
336 	unsigned	offset;
337 	unsigned	length;
338 
339 	/* port any is the conformant culprit */
340 	offset = 24UL;
341 
342 	length = strlen((char *)bahdr->sec_addr.port_spec) + 1;
343 
344 	offset += 2;
345 	offset += length;
346 	offset += (4 - offset) & 3;
347 	offset += sizeof (bahdr->p_result_list);
348 	return (offset);
349 }
350