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