xref: /illumos-gate/usr/src/lib/libmlrpc/common/ndr_marshal.c (revision 3aa6c13072f3d4792a18693e916aed260a496c1f)
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
24  */
25 
26 #include <assert.h>
27 #include <strings.h>
28 #include <sys/param.h>
29 
30 #include <libmlrpc.h>
31 
32 #ifdef _BIG_ENDIAN
33 static const int ndr_native_byte_order = NDR_REPLAB_INTG_BIG_ENDIAN;
34 #else
35 static const int ndr_native_byte_order = NDR_REPLAB_INTG_LITTLE_ENDIAN;
36 #endif
37 
38 static int ndr_decode_hdr_common(ndr_stream_t *, ndr_common_header_t *);
39 static int ndr_decode_pac_hdr(ndr_stream_t *, ndr_pac_hdr_t *);
40 
41 /*
42  * This is the layout of an RPC PDU, as shown in
43  * [MS-RPCE] 2.2.2.13 "Verification Trailer".
44  *
45  *	+-------------------------------+
46  *	|       PDU Header              |
47  *	+-------------------------------+ ====
48  *	|       Stub Data               |
49  *	+-------------------------------+ PDU
50  *	|       Stub Padding Octets     |
51  *	+-------------------------------+ Body
52  *	|       Verification Trailer    |
53  *	+-------------------------------+ Here
54  *	|       Authentication Padding  |
55  *	+-------------------------------+ ====
56  *	|       sec_trailer             |
57  *	+-------------------------------+
58  *	|       Authentication Token    |
59  *	+-------------------------------+
60  *
61  * We don't use the "Verification Trailer" for anything yet.
62  * sec_trailer and Authentication Token are for Secure RPC,
63  * and are collectively the 'auth_verifier_co' in DCERPC.
64  *
65  * Each fragment of a multi-fragment response has a unique
66  * header and, if authentication was requested, a unique
67  * sec_trailer.
68  */
69 
70 static int
71 ndr_convert_nds_error(ndr_stream_t *nds)
72 {
73 	int rc;
74 
75 	switch (nds->error) {
76 	case NDR_ERR_MALLOC_FAILED:
77 		rc = NDR_DRC_FAULT_OUT_OF_MEMORY;
78 		break;
79 
80 	case NDR_ERR_SWITCH_VALUE_INVALID:
81 		rc = NDR_DRC_FAULT_PARAM_0_INVALID;
82 		break;
83 
84 	case NDR_ERR_UNDERFLOW:
85 		rc = NDR_DRC_FAULT_RECEIVED_RUNT;
86 		break;
87 
88 	case NDR_ERR_GROW_FAILED:
89 		rc = NDR_DRC_FAULT_ENCODE_TOO_BIG;
90 		break;
91 
92 	default:
93 		if (nds->m_op == NDR_M_OP_MARSHALL)
94 			rc = NDR_DRC_FAULT_ENCODE_FAILED;
95 		else
96 			rc = NDR_DRC_FAULT_DECODE_FAILED;
97 		break;
98 	}
99 
100 	return (rc);
101 }
102 
103 static int
104 ndr_encode_decode_common(ndr_stream_t *nds, unsigned opnum,
105     ndr_typeinfo_t *ti, void *datum)
106 {
107 	/*
108 	 * Perform the (un)marshalling
109 	 */
110 	if (ndo_operation(nds, ti, opnum, datum))
111 		return (NDR_DRC_OK);
112 
113 	return (ndr_convert_nds_error(nds));
114 }
115 
116 static int
117 ndr_encode_decode_type(ndr_stream_t *nds, ndr_typeinfo_t *ti, void *datum)
118 {
119 	/*
120 	 * Perform the (un)marshalling
121 	 */
122 	if (ndo_process(nds, ti, datum))
123 		return (NDR_DRC_OK);
124 
125 	return (ndr_convert_nds_error(nds));
126 }
127 
128 ndr_buf_t *
129 ndr_buf_init(ndr_typeinfo_t *ti)
130 {
131 	ndr_buf_t		*nbuf;
132 
133 	if ((nbuf = calloc(1, sizeof (ndr_buf_t))) == NULL)
134 		return (NULL);
135 
136 	if ((nbuf->nb_heap = ndr_heap_create()) == NULL) {
137 		free(nbuf);
138 		return (NULL);
139 	}
140 
141 	nbuf->nb_ti = ti;
142 	nbuf->nb_magic = NDR_BUF_MAGIC;
143 	return (nbuf);
144 }
145 
146 void
147 ndr_buf_fini(ndr_buf_t *nbuf)
148 {
149 	assert(nbuf->nb_magic == NDR_BUF_MAGIC);
150 
151 	nds_destruct(&nbuf->nb_nds);
152 	ndr_heap_destroy(nbuf->nb_heap);
153 	nbuf->nb_magic = 0;
154 	free(nbuf);
155 }
156 
157 /*
158  * Decode an NDR encoded buffer.  The buffer is expected to contain
159  * a single fragment packet with a valid PDU header followed by NDR
160  * encoded data.  The structure to which result points should be
161  * of the appropriate type to hold the decoded output.  For example:
162  *
163  *	pac_info_t info;
164  *
165  *	if ((nbuf = ndr_buf_init(&TYPEINFO(ndr_pac)) != NULL) {
166  *		rc = ndr_decode_buf(nbuf, opnum, data, datalen, &info);
167  *		...
168  *		ndr_buf_fini(nbuf);
169  *	}
170  */
171 int
172 ndr_buf_decode(ndr_buf_t *nbuf, unsigned hdr_type, unsigned opnum,
173     const char *data, size_t datalen, void *result)
174 {
175 	ndr_common_header_t	hdr;
176 	ndr_pac_hdr_t		pac_hdr;
177 	unsigned		pdu_size_hint;
178 	int			rc;
179 
180 	assert(nbuf->nb_magic == NDR_BUF_MAGIC);
181 	assert(nbuf->nb_heap != NULL);
182 	assert(nbuf->nb_ti != NULL);
183 
184 	if (datalen < NDR_PDU_SIZE_HINT_DEFAULT)
185 		pdu_size_hint = NDR_PDU_SIZE_HINT_DEFAULT;
186 	else
187 		pdu_size_hint = datalen;
188 
189 	rc = nds_initialize(&nbuf->nb_nds, pdu_size_hint, NDR_MODE_BUF_DECODE,
190 	    nbuf->nb_heap);
191 	if (NDR_DRC_IS_FAULT(rc))
192 		return (rc);
193 
194 	bcopy(data, nbuf->nb_nds.pdu_base_addr, datalen);
195 	nbuf->nb_nds.pdu_size = datalen;
196 
197 	switch (hdr_type) {
198 	case NDR_PTYPE_COMMON:
199 		rc = ndr_decode_hdr_common(&nbuf->nb_nds, &hdr);
200 		if (NDR_DRC_IS_FAULT(rc))
201 			return (rc);
202 
203 		if (!NDR_IS_SINGLE_FRAG(hdr.pfc_flags))
204 			return (NDR_DRC_FAULT_DECODE_FAILED);
205 		break;
206 
207 	case NDR_PTYPE_PAC:
208 		rc = ndr_decode_pac_hdr(&nbuf->nb_nds, &pac_hdr);
209 		if (NDR_DRC_IS_FAULT(rc))
210 			return (rc);
211 
212 		if (pac_hdr.common_hdr.hdrlen != sizeof (ndr_serialtype1_hdr_t))
213 			return (NDR_DRC_FAULT_DECODE_FAILED);
214 		break;
215 
216 	default:
217 		return (NDR_ERR_UNIMPLEMENTED);
218 	}
219 
220 	rc = ndr_encode_decode_common(&nbuf->nb_nds, opnum, nbuf->nb_ti,
221 	    result);
222 	return (rc);
223 }
224 
225 /*
226  * Use the receive stream to unmarshall data (NDR_MODE_CALL_RECV).
227  */
228 int
229 ndr_decode_call(ndr_xa_t *mxa, void *params)
230 {
231 	ndr_stream_t	*nds = &mxa->recv_nds;
232 	int		rc;
233 
234 	if (!NDR_MODE_MATCH(nds, NDR_MODE_CALL_RECV))
235 		return (NDR_DRC_FAULT_MODE_MISMATCH);
236 
237 	rc = ndr_encode_decode_common(nds, mxa->opnum,
238 	    mxa->binding->service->interface_ti, params);
239 
240 	return (rc + NDR_PTYPE_REQUEST);
241 }
242 
243 /*
244  * Use the send stream to marshall data (NDR_MODE_RETURN_SEND).
245  */
246 int
247 ndr_encode_return(ndr_xa_t *mxa, void *params)
248 {
249 	ndr_stream_t	*nds = &mxa->send_nds;
250 	int		rc;
251 
252 	if (!NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND))
253 		return (NDR_DRC_FAULT_MODE_MISMATCH);
254 
255 	rc = ndr_encode_decode_common(nds, mxa->opnum,
256 	    mxa->binding->service->interface_ti, params);
257 
258 	return (rc + NDR_PTYPE_RESPONSE);
259 }
260 
261 /*
262  * Use the send stream to marshall data (NDR_MODE_CALL_SEND).
263  */
264 int
265 ndr_encode_call(ndr_xa_t *mxa, void *params)
266 {
267 	ndr_stream_t	*nds = &mxa->send_nds;
268 	int		rc;
269 
270 	if (!NDR_MODE_MATCH(nds, NDR_MODE_CALL_SEND))
271 		return (NDR_DRC_FAULT_MODE_MISMATCH);
272 
273 	rc = ndr_encode_decode_common(nds, mxa->opnum,
274 	    mxa->binding->service->interface_ti, params);
275 
276 	return (rc + NDR_PTYPE_REQUEST);
277 }
278 
279 /*
280  * Use the receive stream to unmarshall data (NDR_MODE_RETURN_RECV).
281  */
282 int
283 ndr_decode_return(ndr_xa_t *mxa, void *params)
284 {
285 	ndr_stream_t	*nds = &mxa->recv_nds;
286 	int		rc;
287 
288 	if (!NDR_MODE_MATCH(nds, NDR_MODE_RETURN_RECV))
289 		return (NDR_DRC_FAULT_MODE_MISMATCH);
290 
291 	rc = ndr_encode_decode_common(nds, mxa->opnum,
292 	    mxa->binding->service->interface_ti, params);
293 
294 	return (rc + NDR_PTYPE_RESPONSE);
295 }
296 
297 int
298 ndr_decode_pdu_hdr(ndr_xa_t *mxa)
299 {
300 	ndr_common_header_t	*hdr = &mxa->recv_hdr.common_hdr;
301 	ndr_stream_t		*nds = &mxa->recv_nds;
302 	int			rc;
303 	ulong_t			saved_offset;
304 
305 	saved_offset = nds->pdu_scan_offset;
306 	rc = ndr_decode_hdr_common(nds, hdr);
307 	if (NDR_DRC_IS_FAULT(rc))
308 		return (rc);
309 
310 	/*
311 	 * Verify the protocol version.
312 	 */
313 	if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0))
314 		return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED);
315 
316 	mxa->ptype = hdr->ptype;
317 	/* pdu_scan_offset now points to (this fragment's) stub data */
318 	nds->pdu_body_offset = nds->pdu_scan_offset;
319 	nds->pdu_hdr_size = nds->pdu_scan_offset - saved_offset;
320 	nds->pdu_body_size = hdr->frag_length - hdr->auth_length -
321 	    nds->pdu_hdr_size -
322 	    ((hdr->auth_length != 0) ? SEC_TRAILER_SIZE : 0);
323 
324 	if (hdr->auth_length != 0 && hdr->auth_length >
325 	    (hdr->frag_length - nds->pdu_hdr_size - SEC_TRAILER_SIZE))
326 		return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
327 	return (NDR_DRC_OK);
328 }
329 
330 static int
331 ndr_decode_hdr_common(ndr_stream_t *nds, ndr_common_header_t *hdr)
332 {
333 	int			ptype;
334 	int			rc;
335 	int			charset;
336 	int			byte_order;
337 	ulong_t			saved_offset;
338 
339 	if (nds->m_op != NDR_M_OP_UNMARSHALL)
340 		return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH);
341 
342 	/*
343 	 * All PDU headers are at least this big
344 	 */
345 	saved_offset = nds->pdu_scan_offset;
346 	if ((nds->pdu_size - saved_offset) < sizeof (ndr_common_header_t))
347 		return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
348 
349 	/*
350 	 * Peek at the first eight bytes to figure out what we're doing.
351 	 */
352 	rc = NDS_GET_PDU(nds, 0, 8, (char *)hdr, 0, 0);
353 	if (!rc)
354 		return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED);
355 
356 	/*
357 	 * Check for ASCII as the character set.  This is an ASCII
358 	 * versus EBCDIC option and has nothing to do with Unicode.
359 	 */
360 	charset = hdr->packed_drep.intg_char_rep & NDR_REPLAB_CHAR_MASK;
361 	if (charset != NDR_REPLAB_CHAR_ASCII)
362 		return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED);
363 
364 	/*
365 	 * Set the byte swap flag if the PDU byte-order
366 	 * is different from the local byte-order.
367 	 */
368 	byte_order = hdr->packed_drep.intg_char_rep & NDR_REPLAB_INTG_MASK;
369 	nds->swap = (byte_order != ndr_native_byte_order) ? 1 : 0;
370 
371 	ptype = hdr->ptype;
372 	if (ptype == NDR_PTYPE_REQUEST &&
373 	    (hdr->pfc_flags & NDR_PFC_OBJECT_UUID) != 0) {
374 		ptype = NDR_PTYPE_REQUEST_WITH;	/* fake for sizing */
375 	}
376 
377 	rc = ndr_encode_decode_common(nds, ptype, &TYPEINFO(ndr_hdr), hdr);
378 
379 	if (hdr->frag_length > (nds->pdu_size - saved_offset))
380 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
381 	return (NDR_DRC_PTYPE_RPCHDR(rc));
382 }
383 
384 static int
385 ndr_decode_pac_hdr(ndr_stream_t *nds, ndr_pac_hdr_t *hdr)
386 {
387 	int	rc;
388 
389 	if (nds->m_op != NDR_M_OP_UNMARSHALL)
390 		return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH);
391 
392 	/*
393 	 * All PDU headers are at least this big
394 	 */
395 	if ((nds->pdu_size - nds->pdu_scan_offset) < sizeof (ndr_pac_hdr_t))
396 		return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
397 
398 	/*
399 	 * Peek at the first eight bytes to figure out what we're doing.
400 	 */
401 	rc = NDS_GET_PDU(nds, 0, 8, (char *)hdr, 0, 0);
402 	if (!rc)
403 		return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED);
404 
405 	/* Must be set to 1 to indicate type serialization version 1. */
406 	if (hdr->common_hdr.version != 1)
407 		return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED);
408 
409 	/*
410 	 * Set the byte swap flag if the PDU byte-order
411 	 * is different from the local byte-order.
412 	 */
413 	nds->swap =
414 	    (hdr->common_hdr.endianness != ndr_native_byte_order) ? 1 : 0;
415 
416 	rc = ndr_encode_decode_common(nds, NDR_PTYPE_PAC,
417 	    &TYPEINFO(ndr_hdr), hdr);
418 
419 	return (NDR_DRC_PTYPE_RPCHDR(rc));
420 }
421 
422 /*
423  * Decode an RPC fragment header.  Use ndr_decode_pdu_hdr() to process
424  * the first fragment header then this function to process additional
425  * fragment headers.
426  */
427 void
428 ndr_decode_frag_hdr(ndr_stream_t *nds, ndr_common_header_t *hdr)
429 {
430 	ndr_common_header_t *tmp;
431 	uint8_t *pdu;
432 	int byte_order;
433 
434 	pdu = (uint8_t *)nds->pdu_base_offset + nds->pdu_scan_offset;
435 	bcopy(pdu, hdr, NDR_RSP_HDR_SIZE);
436 
437 	/*
438 	 * Swap non-byte fields if the PDU byte-order
439 	 * is different from the local byte-order.
440 	 */
441 	byte_order = hdr->packed_drep.intg_char_rep & NDR_REPLAB_INTG_MASK;
442 
443 	if (byte_order != ndr_native_byte_order) {
444 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
445 		tmp = (ndr_common_header_t *)pdu;
446 
447 		nds_bswap(&tmp->frag_length, &hdr->frag_length,
448 		    sizeof (WORD));
449 		nds_bswap(&tmp->auth_length, &hdr->auth_length,
450 		    sizeof (WORD));
451 		nds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD));
452 	}
453 
454 	/* pdu_scan_offset points to byte 0 of this fragment */
455 	nds->pdu_hdr_size = NDR_RSP_HDR_SIZE;
456 	nds->pdu_body_offset = nds->pdu_scan_offset + nds->pdu_hdr_size;
457 	nds->pdu_body_size = hdr->frag_length - hdr->auth_length -
458 	    nds->pdu_hdr_size -
459 	    ((hdr->auth_length != 0) ? SEC_TRAILER_SIZE : 0);
460 }
461 
462 /*
463  * Remove an RPC fragment header from the received data stream.
464  *
465  * NDR stream on entry:
466  *
467  *                |<--- frag --->|
468  * +-----+--------+-----+--------+-----+---------+-----+
469  * | hdr |  data  | hdr |  data  | hdr |  data   | ... |
470  * +-----+--------+-----+--------+-----+---------+-----+
471  *                 <----
472  *
473  * NDR stream on return:
474  *
475  * +-----+----------------+-----+---------+-----+
476  * | hdr |       data     | hdr |  data   | ... |
477  * +-----+----------------+-----+---------+-----+
478  */
479 void
480 ndr_remove_frag_hdr(ndr_stream_t *nds)
481 {
482 	char	*hdr;
483 	char	*data;
484 	int	nbytes;
485 
486 	hdr = (char *)nds->pdu_base_offset + nds->pdu_scan_offset;
487 	data = hdr + NDR_RSP_HDR_SIZE;
488 	nbytes = nds->pdu_size - nds->pdu_scan_offset - NDR_RSP_HDR_SIZE;
489 
490 	/*
491 	 * Move all of the data after the header back to where the header began.
492 	 */
493 	memmove(hdr, data, nbytes);
494 	nds->pdu_size -= NDR_RSP_HDR_SIZE;
495 }
496 
497 void
498 ndr_show_hdr(ndr_common_header_t *hdr)
499 {
500 	char	*fragtype;
501 
502 	if (hdr == NULL) {
503 		ndo_printf(NULL, NULL, "ndr hdr: <null>");
504 		return;
505 	}
506 
507 	if (NDR_IS_SINGLE_FRAG(hdr->pfc_flags))
508 		fragtype = "single";
509 	else if (NDR_IS_FIRST_FRAG(hdr->pfc_flags))
510 		fragtype = "first";
511 	else if (NDR_IS_LAST_FRAG(hdr->pfc_flags))
512 		fragtype = "last";
513 	else
514 		fragtype = "intermediate";
515 
516 	ndo_printf(NULL, NULL,
517 	    "ndr hdr: %d.%d ptype=%d, %s frag (flags=0x%08x) len=%d "
518 	    "auth_len=%d",
519 	    hdr->rpc_vers, hdr->rpc_vers_minor, hdr->ptype,
520 	    fragtype, hdr->pfc_flags, hdr->frag_length, hdr->auth_length);
521 }
522 
523 void
524 ndr_show_auth(ndr_sec_t *auth)
525 {
526 	if (auth == NULL) {
527 		ndo_printf(NULL, NULL, "ndr auth: <null>");
528 		return;
529 	}
530 
531 	ndo_printf(NULL, NULL,
532 	    "ndr auth: type=0x%x, level=0x%x, pad_len=%d, ctx_id=%d",
533 	    auth->auth_type, auth->auth_level, auth->auth_pad_len,
534 	    auth->auth_context_id);
535 }
536 
537 int
538 ndr_encode_pdu_hdr(ndr_xa_t *mxa)
539 {
540 	ndr_common_header_t	*hdr = &mxa->send_hdr.common_hdr;
541 	ndr_stream_t		*nds = &mxa->send_nds;
542 	int			ptype;
543 	int			rc;
544 
545 	if (nds->m_op != NDR_M_OP_MARSHALL)
546 		return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH);
547 
548 	ptype = hdr->ptype;
549 	if (ptype == NDR_PTYPE_REQUEST &&
550 	    (hdr->pfc_flags & NDR_PFC_OBJECT_UUID) != 0) {
551 		ptype = NDR_PTYPE_REQUEST_WITH;	/* fake for sizing */
552 	}
553 
554 	rc = ndr_encode_decode_common(nds, ptype, &TYPEINFO(ndr_hdr), hdr);
555 
556 	return (NDR_DRC_PTYPE_RPCHDR(rc));
557 }
558 
559 /*
560  * This is a hand-coded derivative of the automatically generated
561  * (un)marshalling routine for bind_ack headers. bind_ack headers
562  * have an interior conformant array, which is inconsistent with
563  * IDL/NDR rules.
564  */
565 extern struct ndr_typeinfo ndt__uchar;
566 extern struct ndr_typeinfo ndt__ushort;
567 extern struct ndr_typeinfo ndt__ulong;
568 
569 int ndr__ndr_bind_ack_hdr(ndr_ref_t *encl_ref);
570 ndr_typeinfo_t ndt__ndr_bind_ack_hdr = {
571     1,		/* NDR version */
572     3,		/* alignment */
573     NDR_F_STRUCT,	/* flags */
574     ndr__ndr_bind_ack_hdr,	/* ndr_func */
575     68,		/* pdu_size_fixed_part */
576     0,		/* pdu_size_variable_part */
577     68,		/* c_size_fixed_part */
578     0,		/* c_size_variable_part */
579 };
580 
581 /*
582  * [_no_reorder]
583  */
584 int
585 ndr__ndr_bind_ack_hdr(ndr_ref_t *encl_ref)
586 {
587 	ndr_stream_t		*nds = encl_ref->stream;
588 	struct ndr_bind_ack_hdr	*val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
589 	    (struct ndr_bind_ack_hdr *)encl_ref->datum;
590 	ndr_ref_t		myref;
591 	unsigned long		offset;
592 
593 	bzero(&myref, sizeof (myref));
594 	myref.enclosing = encl_ref;
595 	myref.stream = encl_ref->stream;
596 	myref.packed_alignment = 0;
597 
598 	/* do all members in order */
599 	NDR_MEMBER(_ndr_common_header, common_hdr, 0UL);
600 	NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
601 	NDR_MEMBER(_ushort, max_recv_frag, 18UL);
602 	NDR_MEMBER(_ulong, assoc_group_id, 20UL);
603 
604 	/* port any is the conformant culprit */
605 	offset = 24UL;
606 
607 	switch (nds->m_op) {
608 	case NDR_M_OP_MARSHALL:
609 		val->sec_addr.length =
610 		    strlen((char *)val->sec_addr.port_spec) + 1;
611 		break;
612 
613 	case NDR_M_OP_UNMARSHALL:
614 		break;
615 
616 	default:
617 		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
618 		return (0);
619 	}
620 
621 	NDR_MEMBER(_ushort, sec_addr.length, offset);
622 	NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
623 	    offset+2UL, val->sec_addr.length);
624 
625 	offset += 2;
626 	offset += val->sec_addr.length;
627 	offset += NDR_ALIGN4(offset);
628 
629 	NDR_MEMBER(_ndr_p_result_list, p_result_list, offset);
630 	return (1);
631 }
632 
633 /*
634  * Assume a single presentation context element in the result list.
635  */
636 unsigned
637 ndr_bind_ack_hdr_size(ndr_xa_t *mxa)
638 {
639 	ndr_bind_ack_hdr_t *bahdr = &mxa->send_hdr.bind_ack_hdr;
640 	unsigned	offset;
641 	unsigned	length;
642 
643 	/* port any is the conformant culprit */
644 	offset = 24UL;
645 
646 	length = strlen((char *)bahdr->sec_addr.port_spec) + 1;
647 
648 	offset += 2;
649 	offset += length;
650 	offset += NDR_ALIGN4(offset);
651 	offset += sizeof (ndr_p_result_list_t);
652 	return (offset);
653 }
654 
655 /*
656  * This is a hand-coded derivative of the automatically generated
657  * (un)marshalling routine for alter_context_rsp headers.
658  * Alter context response headers have an interior conformant array,
659  * which is inconsistent with IDL/NDR rules.
660  */
661 int ndr__ndr_alter_context_rsp_hdr(ndr_ref_t *encl_ref);
662 ndr_typeinfo_t ndt__ndr_alter_context_rsp_hdr = {
663     1,			/* NDR version */
664     3,			/* alignment */
665     NDR_F_STRUCT,	/* flags */
666     ndr__ndr_alter_context_rsp_hdr,	/* ndr_func */
667     56,			/* pdu_size_fixed_part */
668     0,			/* pdu_size_variable_part */
669     56,			/* c_size_fixed_part */
670     0,			/* c_size_variable_part */
671 };
672 
673 /*
674  * [_no_reorder]
675  */
676 int
677 ndr__ndr_alter_context_rsp_hdr(ndr_ref_t *encl_ref)
678 {
679 	ndr_stream_t		*nds = encl_ref->stream;
680 	ndr_alter_context_rsp_hdr_t *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/
681 	    (ndr_alter_context_rsp_hdr_t *)encl_ref->datum;
682 	ndr_ref_t		myref;
683 	unsigned long		offset;
684 
685 	bzero(&myref, sizeof (myref));
686 	myref.enclosing = encl_ref;
687 	myref.stream = encl_ref->stream;
688 	myref.packed_alignment = 0;
689 
690 	/* do all members in order */
691 	NDR_MEMBER(_ndr_common_header, common_hdr, 0UL);
692 	NDR_MEMBER(_ushort, max_xmit_frag, 16UL);
693 	NDR_MEMBER(_ushort, max_recv_frag, 18UL);
694 	NDR_MEMBER(_ulong, assoc_group_id, 20UL);
695 
696 	offset = 24UL;	/* offset of sec_addr */
697 
698 	switch (nds->m_op) {
699 	case NDR_M_OP_MARSHALL:
700 		val->sec_addr.length = 0;
701 		break;
702 
703 	case NDR_M_OP_UNMARSHALL:
704 		break;
705 
706 	default:
707 		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
708 		return (0);
709 	}
710 
711 	NDR_MEMBER(_ushort, sec_addr.length, offset);
712 	NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec,
713 	    offset+2UL, val->sec_addr.length);
714 
715 	offset += 2;	/* sizeof (sec_addr.length) */
716 	offset += NDR_ALIGN4(offset);
717 
718 	NDR_MEMBER(_ndr_p_result_list, p_result_list, offset);
719 	return (1);
720 }
721 
722 /*
723  * Assume a single presentation context element in the result list.
724  */
725 unsigned
726 ndr_alter_context_rsp_hdr_size(void)
727 {
728 	unsigned	offset;
729 
730 	offset = 24UL;	/* offset of sec_addr */
731 	offset += 2;	/* sizeof (sec_addr.length) */
732 	offset += NDR_ALIGN4(offset);
733 	offset += sizeof (ndr_p_result_list_t);
734 	return (offset);
735 }
736 
737 /*
738  * This is a hand-coded (un)marshalling routine for auth_verifier_co
739  * (aka ndr_sec_t).
740  *
741  * We need to pretend this structure isn't variably sized, until ndrgen
742  * has been modified to support variable-sized arrays.
743  * Here, we only account for the fixed-size members (8 bytes), plus
744  * a pointer for the C structure.
745  *
746  * We then convert between a pointer to the auth token (auth_value,
747  * allocated here during unmarshall) and a flat, 'fixed'-sized array.
748  */
749 
750 int ndr__auth_verifier_co(ndr_ref_t *encl_ref);
751 ndr_typeinfo_t ndt__auth_verifier_co = {
752     1,		/* NDR version */
753     3,		/* alignment */
754     NDR_F_STRUCT,	/* flags */
755     ndr__auth_verifier_co,	/* ndr_func */
756     8,		/* pdu_size_fixed_part */
757     0,		/* pdu_size_variable_part */
758     8 + sizeof (void *),	/* c_size_fixed_part */
759     0,		/* c_size_variable_part */
760 };
761 
762 /*
763  * [_no_reorder]
764  */
765 int
766 ndr__auth_verifier_co(ndr_ref_t *encl_ref)
767 {
768 	ndr_stream_t		*nds = encl_ref->stream;
769 	ndr_xa_t		*mxa = /*LINTED E_BAD_PTR_CAST_ALIGN*/
770 	    (ndr_xa_t *)encl_ref->datum;
771 	ndr_common_header_t	*hdr;
772 	ndr_ref_t		myref;
773 	ndr_sec_t		*val;
774 
775 	/*
776 	 * Assumes scan_offset points to the end of PDU body.
777 	 * (That's base + frag_len - auth_len - SEC_TRAILER_SIZE)
778 	 *
779 	 * At some point, NDRGEN could use struct initializers instead of
780 	 * bzero() + initialization.
781 	 */
782 	bzero(&myref, sizeof (myref));
783 	myref.enclosing = encl_ref;
784 	myref.stream = encl_ref->stream;
785 
786 	switch (nds->m_op) {
787 	case NDR_M_OP_MARSHALL:
788 		val = &mxa->send_auth;
789 		hdr = &mxa->send_hdr.common_hdr;
790 		break;
791 
792 	case NDR_M_OP_UNMARSHALL:
793 		val = &mxa->recv_auth;
794 		hdr = &mxa->recv_hdr.common_hdr;
795 		val->auth_value = (uchar_t *)NDS_MALLOC(nds, hdr->auth_length,
796 		    encl_ref);
797 		break;
798 
799 	default:
800 		NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
801 		return (0);
802 	}
803 
804 	/*
805 	 * ndr_topmost() can't account for auth_length (pdu_scan/end_offset).
806 	 * This would only matter if any of this struct's members
807 	 * are treated as 'outer' constructs, but they aren't.
808 	 */
809 	encl_ref->pdu_end_offset += hdr->auth_length;
810 	nds->pdu_scan_offset += hdr->auth_length;
811 
812 	NDR_MEMBER(_uchar, auth_type, 0UL);
813 	NDR_MEMBER(_uchar, auth_level, 1UL);
814 	NDR_MEMBER(_uchar, auth_pad_len, 2UL);
815 	NDR_MEMBER(_uchar, auth_rsvd, 3UL);
816 	NDR_MEMBER(_ulong, auth_context_id, 4UL);
817 
818 	NDR_MEMBER_PTR_WITH_DIMENSION(_uchar, auth_value, 8UL,
819 	    hdr->auth_length);
820 
821 	return (1);
822 }
823 
824 int
825 ndr_encode_pdu_auth(ndr_xa_t *mxa)
826 {
827 	ndr_common_header_t	*hdr = &mxa->send_hdr.common_hdr;
828 	ndr_stream_t		*nds = &mxa->send_nds;
829 	int			rc;
830 	ulong_t			want_size;
831 
832 	if (nds->m_op != NDR_M_OP_MARSHALL)
833 		return (NDR_DRC_FAULT_MODE_MISMATCH);
834 
835 	if (hdr->auth_length == 0)
836 		return (NDR_DRC_OK);
837 
838 	want_size = nds->pdu_scan_offset + hdr->auth_length + SEC_TRAILER_SIZE;
839 
840 	/*
841 	 * Make sure we have space for the sec trailer - the marshaller
842 	 * doesn't know how large the auth token is.
843 	 * Note: ndr_add_auth_token() has already added padding.
844 	 *
845 	 * NDS_GROW_PDU will adjust pdu_size for us.
846 	 */
847 	if (nds->pdu_max_size < want_size) {
848 		if (NDS_GROW_PDU(nds, want_size, NULL) == 0)
849 			return (NDR_DRC_FAULT_ENCODE_TOO_BIG);
850 	} else {
851 		nds->pdu_size = want_size;
852 	}
853 	rc = ndr_encode_decode_type(nds, &TYPEINFO(auth_verifier_co),
854 	    mxa);
855 
856 	return (rc);
857 }
858 
859 int
860 ndr_decode_pdu_auth(ndr_xa_t *mxa)
861 {
862 	ndr_common_header_t	*hdr = &mxa->recv_hdr.common_hdr;
863 	ndr_stream_t		*nds = &mxa->recv_nds;
864 	ndr_sec_t		*auth = &mxa->recv_auth;
865 	int			rc;
866 	ulong_t			saved_offset;
867 	size_t			auth_size;
868 
869 	if (nds->m_op != NDR_M_OP_UNMARSHALL)
870 		return (NDR_DRC_FAULT_MODE_MISMATCH);
871 
872 	mxa->recv_auth.auth_pad_len = 0;
873 	if (hdr->auth_length == 0)
874 		return (NDR_DRC_OK);
875 
876 	/*
877 	 * Save the current offset, and skip to the sec_trailer.
878 	 * That's located after the (fragment of) stub data and the auth
879 	 * pad bytes (collectively the 'PDU Body').
880 	 */
881 	saved_offset = nds->pdu_scan_offset;
882 	nds->pdu_scan_offset = nds->pdu_body_offset + nds->pdu_body_size;
883 
884 	/* auth_length is all of the data after the sec_trailer */
885 	if (hdr->auth_length >
886 	    (nds->pdu_size - nds->pdu_scan_offset - SEC_TRAILER_SIZE)) {
887 		nds->pdu_scan_offset = saved_offset;
888 		return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
889 	}
890 
891 	rc = ndr_encode_decode_type(nds, &TYPEINFO(auth_verifier_co),
892 	    mxa);
893 
894 	/*
895 	 * Reset the scan_offset for call decode processing.
896 	 * If we were successful, remove the sec trailer and padding
897 	 * from size accounting.
898 	 */
899 	if (auth->auth_pad_len > nds->pdu_body_size)
900 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
901 	else if (rc == NDR_DRC_OK) {
902 		auth_size = hdr->auth_length + SEC_TRAILER_SIZE +
903 		    auth->auth_pad_len;
904 
905 		/*
906 		 * After the authenticator has been decoded,
907 		 * pdu_scan_offset points to just after the auth token,
908 		 * which is the end of the fragment.
909 		 *
910 		 * If there's no data after the authenticator, then we
911 		 * just remove the authenticator from size accounting.
912 		 * Otherwise, need to memmove() all of that data back to after
913 		 * the stub data. The data we move starts at the beginning of
914 		 * the next fragment.
915 		 */
916 		if (nds->pdu_size > nds->pdu_scan_offset) {
917 			uchar_t *next_frag_ptr = nds->pdu_base_addr +
918 			    nds->pdu_scan_offset;
919 
920 			memmove(next_frag_ptr - auth_size, next_frag_ptr,
921 			    nds->pdu_size - nds->pdu_scan_offset);
922 		}
923 
924 		nds->pdu_size -= auth_size;
925 	}
926 	nds->pdu_scan_offset = saved_offset;
927 	return (rc);
928 }
929