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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 #include <sys/param.h>
33 static const int ndr_native_byte_order
= NDR_REPLAB_INTG_BIG_ENDIAN
;
35 static const int ndr_native_byte_order
= NDR_REPLAB_INTG_LITTLE_ENDIAN
;
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
*);
42 ndr_encode_decode_common(ndr_stream_t
*nds
, unsigned opnum
,
43 ndr_typeinfo_t
*ti
, void *datum
)
48 * Perform the (un)marshalling
50 if (ndo_operation(nds
, ti
, opnum
, datum
))
54 case NDR_ERR_MALLOC_FAILED
:
55 rc
= NDR_DRC_FAULT_OUT_OF_MEMORY
;
58 case NDR_ERR_SWITCH_VALUE_INVALID
:
59 rc
= NDR_DRC_FAULT_PARAM_0_INVALID
;
62 case NDR_ERR_UNDERFLOW
:
63 rc
= NDR_DRC_FAULT_RECEIVED_RUNT
;
66 case NDR_ERR_GROW_FAILED
:
67 rc
= NDR_DRC_FAULT_ENCODE_TOO_BIG
;
71 if (nds
->m_op
== NDR_M_OP_MARSHALL
)
72 rc
= NDR_DRC_FAULT_ENCODE_FAILED
;
74 rc
= NDR_DRC_FAULT_DECODE_FAILED
;
82 ndr_buf_init(ndr_typeinfo_t
*ti
)
86 if ((nbuf
= calloc(1, sizeof (ndr_buf_t
))) == NULL
)
89 if ((nbuf
->nb_heap
= ndr_heap_create()) == NULL
) {
95 nbuf
->nb_magic
= NDR_BUF_MAGIC
;
100 ndr_buf_fini(ndr_buf_t
*nbuf
)
102 assert(nbuf
->nb_magic
== NDR_BUF_MAGIC
);
104 nds_destruct(&nbuf
->nb_nds
);
105 ndr_heap_destroy(nbuf
->nb_heap
);
111 * Decode an NDR encoded buffer. The buffer is expected to contain
112 * a single fragment packet with a valid PDU header followed by NDR
113 * encoded data. The structure to which result points should be
114 * of the appropriate type to hold the decoded output. For example:
118 * if ((nbuf = ndr_buf_init(&TYPEINFO(ndr_pac)) != NULL) {
119 * rc = ndr_decode_buf(nbuf, opnum, data, datalen, &info);
121 * ndr_buf_fini(nbuf);
125 ndr_buf_decode(ndr_buf_t
*nbuf
, unsigned hdr_type
, unsigned opnum
,
126 const char *data
, size_t datalen
, void *result
)
128 ndr_common_header_t hdr
;
129 ndr_pac_hdr_t pac_hdr
;
130 unsigned pdu_size_hint
;
133 assert(nbuf
->nb_magic
== NDR_BUF_MAGIC
);
134 assert(nbuf
->nb_heap
!= NULL
);
135 assert(nbuf
->nb_ti
!= NULL
);
137 if (datalen
< NDR_PDU_SIZE_HINT_DEFAULT
)
138 pdu_size_hint
= NDR_PDU_SIZE_HINT_DEFAULT
;
140 pdu_size_hint
= datalen
;
142 rc
= nds_initialize(&nbuf
->nb_nds
, pdu_size_hint
, NDR_MODE_BUF_DECODE
,
144 if (NDR_DRC_IS_FAULT(rc
))
147 bcopy(data
, nbuf
->nb_nds
.pdu_base_addr
, datalen
);
150 case NDR_PTYPE_COMMON
:
151 rc
= ndr_decode_hdr_common(&nbuf
->nb_nds
, &hdr
);
152 if (NDR_DRC_IS_FAULT(rc
))
155 if (!NDR_IS_SINGLE_FRAG(hdr
.pfc_flags
))
156 return (NDR_DRC_FAULT_DECODE_FAILED
);
160 rc
= ndr_decode_pac_hdr(&nbuf
->nb_nds
, &pac_hdr
);
161 if (NDR_DRC_IS_FAULT(rc
))
164 if (pac_hdr
.common_hdr
.hdrlen
!= sizeof (ndr_serialtype1_hdr_t
))
165 return (NDR_DRC_FAULT_DECODE_FAILED
);
169 return (NDR_ERR_UNIMPLEMENTED
);
172 rc
= ndr_encode_decode_common(&nbuf
->nb_nds
, opnum
, nbuf
->nb_ti
,
178 * Use the receive stream to unmarshall data (NDR_MODE_CALL_RECV).
181 ndr_decode_call(ndr_xa_t
*mxa
, void *params
)
183 ndr_stream_t
*nds
= &mxa
->recv_nds
;
186 if (!NDR_MODE_MATCH(nds
, NDR_MODE_CALL_RECV
))
187 return (NDR_DRC_FAULT_MODE_MISMATCH
);
189 rc
= ndr_encode_decode_common(nds
, mxa
->opnum
,
190 mxa
->binding
->service
->interface_ti
, params
);
192 return (rc
+ NDR_PTYPE_REQUEST
);
196 * Use the send stream to marshall data (NDR_MODE_RETURN_SEND).
199 ndr_encode_return(ndr_xa_t
*mxa
, void *params
)
201 ndr_stream_t
*nds
= &mxa
->send_nds
;
204 if (!NDR_MODE_MATCH(nds
, NDR_MODE_RETURN_SEND
))
205 return (NDR_DRC_FAULT_MODE_MISMATCH
);
207 rc
= ndr_encode_decode_common(nds
, mxa
->opnum
,
208 mxa
->binding
->service
->interface_ti
, params
);
210 return (rc
+ NDR_PTYPE_RESPONSE
);
214 * Use the send stream to marshall data (NDR_MODE_CALL_SEND).
217 ndr_encode_call(ndr_xa_t
*mxa
, void *params
)
219 ndr_stream_t
*nds
= &mxa
->send_nds
;
222 if (!NDR_MODE_MATCH(nds
, NDR_MODE_CALL_SEND
))
223 return (NDR_DRC_FAULT_MODE_MISMATCH
);
225 rc
= ndr_encode_decode_common(nds
, mxa
->opnum
,
226 mxa
->binding
->service
->interface_ti
, params
);
228 return (rc
+ NDR_PTYPE_REQUEST
);
232 * Use the receive stream to unmarshall data (NDR_MODE_RETURN_RECV).
235 ndr_decode_return(ndr_xa_t
*mxa
, void *params
)
237 ndr_stream_t
*nds
= &mxa
->recv_nds
;
240 if (!NDR_MODE_MATCH(nds
, NDR_MODE_RETURN_RECV
))
241 return (NDR_DRC_FAULT_MODE_MISMATCH
);
243 rc
= ndr_encode_decode_common(nds
, mxa
->opnum
,
244 mxa
->binding
->service
->interface_ti
, params
);
246 return (rc
+ NDR_PTYPE_RESPONSE
);
250 ndr_decode_pdu_hdr(ndr_xa_t
*mxa
)
252 ndr_common_header_t
*hdr
= &mxa
->recv_hdr
.common_hdr
;
253 ndr_stream_t
*nds
= &mxa
->recv_nds
;
256 rc
= ndr_decode_hdr_common(nds
, hdr
);
257 if (NDR_DRC_IS_FAULT(rc
))
261 * Verify the protocol version.
263 if ((hdr
->rpc_vers
!= 5) || (hdr
->rpc_vers_minor
!= 0))
264 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED
);
266 mxa
->ptype
= hdr
->ptype
;
271 ndr_decode_hdr_common(ndr_stream_t
*nds
, ndr_common_header_t
*hdr
)
278 if (nds
->m_op
!= NDR_M_OP_UNMARSHALL
)
279 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH
);
282 * All PDU headers are at least this big
284 rc
= NDS_GROW_PDU(nds
, sizeof (ndr_common_header_t
), 0);
286 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT
);
289 * Peek at the first eight bytes to figure out what we're doing.
291 rc
= NDS_GET_PDU(nds
, 0, 8, (char *)hdr
, 0, 0);
293 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED
);
296 * Check for ASCII as the character set. This is an ASCII
297 * versus EBCDIC option and has nothing to do with Unicode.
299 charset
= hdr
->packed_drep
.intg_char_rep
& NDR_REPLAB_CHAR_MASK
;
300 if (charset
!= NDR_REPLAB_CHAR_ASCII
)
301 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED
);
304 * Set the byte swap flag if the PDU byte-order
305 * is different from the local byte-order.
307 byte_order
= hdr
->packed_drep
.intg_char_rep
& NDR_REPLAB_INTG_MASK
;
308 nds
->swap
= (byte_order
!= ndr_native_byte_order
) ? 1 : 0;
311 if (ptype
== NDR_PTYPE_REQUEST
&&
312 (hdr
->pfc_flags
& NDR_PFC_OBJECT_UUID
) != 0) {
313 ptype
= NDR_PTYPE_REQUEST_WITH
; /* fake for sizing */
316 rc
= ndr_encode_decode_common(nds
, ptype
, &TYPEINFO(ndr_hdr
), hdr
);
318 return (NDR_DRC_PTYPE_RPCHDR(rc
));
322 ndr_decode_pac_hdr(ndr_stream_t
*nds
, ndr_pac_hdr_t
*hdr
)
326 if (nds
->m_op
!= NDR_M_OP_UNMARSHALL
)
327 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH
);
330 * All PDU headers are at least this big
332 rc
= NDS_GROW_PDU(nds
, sizeof (ndr_pac_hdr_t
), 0);
334 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT
);
337 * Peek at the first eight bytes to figure out what we're doing.
339 rc
= NDS_GET_PDU(nds
, 0, 8, (char *)hdr
, 0, 0);
341 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED
);
343 /* Must be set to 1 to indicate type serialization version 1. */
344 if (hdr
->common_hdr
.version
!= 1)
345 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED
);
348 * Set the byte swap flag if the PDU byte-order
349 * is different from the local byte-order.
352 (hdr
->common_hdr
.endianness
!= ndr_native_byte_order
) ? 1 : 0;
354 rc
= ndr_encode_decode_common(nds
, NDR_PTYPE_PAC
,
355 &TYPEINFO(ndr_hdr
), hdr
);
357 return (NDR_DRC_PTYPE_RPCHDR(rc
));
361 * Decode an RPC fragment header. Use ndr_decode_pdu_hdr() to process
362 * the first fragment header then this function to process additional
366 ndr_decode_frag_hdr(ndr_stream_t
*nds
, ndr_common_header_t
*hdr
)
368 ndr_common_header_t
*tmp
;
372 pdu
= (uint8_t *)nds
->pdu_base_offset
+ nds
->pdu_scan_offset
;
373 bcopy(pdu
, hdr
, NDR_RSP_HDR_SIZE
);
376 * Swap non-byte fields if the PDU byte-order
377 * is different from the local byte-order.
379 byte_order
= hdr
->packed_drep
.intg_char_rep
& NDR_REPLAB_INTG_MASK
;
381 if (byte_order
!= ndr_native_byte_order
) {
382 /*LINTED E_BAD_PTR_CAST_ALIGN*/
383 tmp
= (ndr_common_header_t
*)pdu
;
385 nds_bswap(&tmp
->frag_length
, &hdr
->frag_length
,
387 nds_bswap(&tmp
->auth_length
, &hdr
->auth_length
,
389 nds_bswap(&tmp
->call_id
, &hdr
->call_id
, sizeof (DWORD
));
394 * Remove an RPC fragment header from the received data stream.
396 * NDR stream on entry:
399 * +-----+--------+-----+--------+-----+---------+-----+
400 * | hdr | data | hdr | data | hdr | data | ... |
401 * +-----+--------+-----+--------+-----+---------+-----+
404 * NDR stream on return:
406 * +-----+----------------+-----+---------+-----+
407 * | hdr | data | hdr | data | ... |
408 * +-----+----------------+-----+---------+-----+
411 ndr_remove_frag_hdr(ndr_stream_t
*nds
)
417 hdr
= (char *)nds
->pdu_base_offset
+ nds
->pdu_scan_offset
;
418 data
= hdr
+ NDR_RSP_HDR_SIZE
;
419 nbytes
= nds
->pdu_size
- nds
->pdu_scan_offset
- NDR_RSP_HDR_SIZE
;
421 bcopy(data
, hdr
, nbytes
);
422 nds
->pdu_size
-= NDR_RSP_HDR_SIZE
;
426 ndr_show_hdr(ndr_common_header_t
*hdr
)
431 ndo_printf(NULL
, NULL
, "ndr hdr: <null>");
435 if (NDR_IS_SINGLE_FRAG(hdr
->pfc_flags
))
437 else if (NDR_IS_FIRST_FRAG(hdr
->pfc_flags
))
439 else if (NDR_IS_LAST_FRAG(hdr
->pfc_flags
))
442 fragtype
= "intermediate";
444 ndo_printf(NULL
, NULL
,
445 "ndr hdr: %d.%d ptype=%d, %s frag (flags=0x%08x) len=%d",
446 hdr
->rpc_vers
, hdr
->rpc_vers_minor
, hdr
->ptype
,
447 fragtype
, hdr
->pfc_flags
, hdr
->frag_length
);
451 ndr_encode_pdu_hdr(ndr_xa_t
*mxa
)
453 ndr_common_header_t
*hdr
= &mxa
->send_hdr
.common_hdr
;
454 ndr_stream_t
*nds
= &mxa
->send_nds
;
458 if (nds
->m_op
!= NDR_M_OP_MARSHALL
)
459 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH
);
462 if (ptype
== NDR_PTYPE_REQUEST
&&
463 (hdr
->pfc_flags
& NDR_PFC_OBJECT_UUID
) != 0) {
464 ptype
= NDR_PTYPE_REQUEST_WITH
; /* fake for sizing */
467 rc
= ndr_encode_decode_common(nds
, ptype
, &TYPEINFO(ndr_hdr
), hdr
);
469 return (NDR_DRC_PTYPE_RPCHDR(rc
));
473 * This is a hand-coded derivative of the automatically generated
474 * (un)marshalling routine for bind_ack headers. bind_ack headers
475 * have an interior conformant array, which is inconsistent with
478 extern struct ndr_typeinfo ndt__uchar
;
479 extern struct ndr_typeinfo ndt__ushort
;
480 extern struct ndr_typeinfo ndt__ulong
;
482 int ndr__ndr_bind_ack_hdr(ndr_ref_t
*encl_ref
);
483 ndr_typeinfo_t ndt__ndr_bind_ack_hdr
= {
486 NDR_F_STRUCT
, /* flags */
487 ndr__ndr_bind_ack_hdr
, /* ndr_func */
488 68, /* pdu_size_fixed_part */
489 0, /* pdu_size_variable_part */
490 68, /* c_size_fixed_part */
491 0, /* c_size_variable_part */
498 ndr__ndr_bind_ack_hdr(ndr_ref_t
*encl_ref
)
500 ndr_stream_t
*nds
= encl_ref
->stream
;
501 struct ndr_bind_ack_hdr
*val
= /*LINTED E_BAD_PTR_CAST_ALIGN*/
502 (struct ndr_bind_ack_hdr
*)encl_ref
->datum
;
504 unsigned long offset
;
506 bzero(&myref
, sizeof (myref
));
507 myref
.enclosing
= encl_ref
;
508 myref
.stream
= encl_ref
->stream
;
509 myref
.packed_alignment
= 0;
511 /* do all members in order */
512 NDR_MEMBER(_ndr_common_header
, common_hdr
, 0UL);
513 NDR_MEMBER(_ushort
, max_xmit_frag
, 16UL);
514 NDR_MEMBER(_ushort
, max_recv_frag
, 18UL);
515 NDR_MEMBER(_ulong
, assoc_group_id
, 20UL);
517 /* port any is the conformant culprit */
521 case NDR_M_OP_MARSHALL
:
522 val
->sec_addr
.length
=
523 strlen((char *)val
->sec_addr
.port_spec
) + 1;
526 case NDR_M_OP_UNMARSHALL
:
530 NDR_SET_ERROR(encl_ref
, NDR_ERR_M_OP_INVALID
);
534 NDR_MEMBER(_ushort
, sec_addr
.length
, offset
);
535 NDR_MEMBER_ARR_WITH_DIMENSION(_uchar
, sec_addr
.port_spec
,
536 offset
+2UL, val
->sec_addr
.length
);
539 offset
+= val
->sec_addr
.length
;
540 offset
+= NDR_ALIGN4(offset
);
542 NDR_MEMBER(_ndr_p_result_list
, p_result_list
, offset
);
547 * Assume a single presentation context element in the result list.
550 ndr_bind_ack_hdr_size(ndr_xa_t
*mxa
)
552 ndr_bind_ack_hdr_t
*bahdr
= &mxa
->send_hdr
.bind_ack_hdr
;
556 /* port any is the conformant culprit */
559 length
= strlen((char *)bahdr
->sec_addr
.port_spec
) + 1;
563 offset
+= NDR_ALIGN4(offset
);
564 offset
+= sizeof (ndr_p_result_list_t
);
569 * This is a hand-coded derivative of the automatically generated
570 * (un)marshalling routine for alter_context_rsp headers.
571 * Alter context response headers have an interior conformant array,
572 * which is inconsistent with IDL/NDR rules.
574 int ndr__ndr_alter_context_rsp_hdr(ndr_ref_t
*encl_ref
);
575 ndr_typeinfo_t ndt__ndr_alter_context_rsp_hdr
= {
578 NDR_F_STRUCT
, /* flags */
579 ndr__ndr_alter_context_rsp_hdr
, /* ndr_func */
580 56, /* pdu_size_fixed_part */
581 0, /* pdu_size_variable_part */
582 56, /* c_size_fixed_part */
583 0, /* c_size_variable_part */
590 ndr__ndr_alter_context_rsp_hdr(ndr_ref_t
*encl_ref
)
592 ndr_stream_t
*nds
= encl_ref
->stream
;
593 ndr_alter_context_rsp_hdr_t
*val
= /*LINTED E_BAD_PTR_CAST_ALIGN*/
594 (ndr_alter_context_rsp_hdr_t
*)encl_ref
->datum
;
596 unsigned long offset
;
598 bzero(&myref
, sizeof (myref
));
599 myref
.enclosing
= encl_ref
;
600 myref
.stream
= encl_ref
->stream
;
601 myref
.packed_alignment
= 0;
603 /* do all members in order */
604 NDR_MEMBER(_ndr_common_header
, common_hdr
, 0UL);
605 NDR_MEMBER(_ushort
, max_xmit_frag
, 16UL);
606 NDR_MEMBER(_ushort
, max_recv_frag
, 18UL);
607 NDR_MEMBER(_ulong
, assoc_group_id
, 20UL);
609 offset
= 24UL; /* offset of sec_addr */
612 case NDR_M_OP_MARSHALL
:
613 val
->sec_addr
.length
= 0;
616 case NDR_M_OP_UNMARSHALL
:
620 NDR_SET_ERROR(encl_ref
, NDR_ERR_M_OP_INVALID
);
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
);
628 offset
+= 2; /* sizeof (sec_addr.length) */
629 offset
+= NDR_ALIGN4(offset
);
631 NDR_MEMBER(_ndr_p_result_list
, p_result_list
, offset
);
636 * Assume a single presentation context element in the result list.
639 ndr_alter_context_rsp_hdr_size(void)
643 offset
= 24UL; /* offset of sec_addr */
644 offset
+= 2; /* sizeof (sec_addr.length) */
645 offset
+= NDR_ALIGN4(offset
);
646 offset
+= sizeof (ndr_p_result_list_t
);