Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / libmlrpc / common / ndr_marshal.c
blob4d34030d2a758fe96918068c0c70010d48f823d7
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 #include <assert.h>
27 #include <strings.h>
28 #include <sys/param.h>
30 #include <libmlrpc.h>
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
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 *);
41 static int
42 ndr_encode_decode_common(ndr_stream_t *nds, unsigned opnum,
43 ndr_typeinfo_t *ti, void *datum)
45 int rc;
48 * Perform the (un)marshalling
50 if (ndo_operation(nds, ti, opnum, datum))
51 return (NDR_DRC_OK);
53 switch (nds->error) {
54 case NDR_ERR_MALLOC_FAILED:
55 rc = NDR_DRC_FAULT_OUT_OF_MEMORY;
56 break;
58 case NDR_ERR_SWITCH_VALUE_INVALID:
59 rc = NDR_DRC_FAULT_PARAM_0_INVALID;
60 break;
62 case NDR_ERR_UNDERFLOW:
63 rc = NDR_DRC_FAULT_RECEIVED_RUNT;
64 break;
66 case NDR_ERR_GROW_FAILED:
67 rc = NDR_DRC_FAULT_ENCODE_TOO_BIG;
68 break;
70 default:
71 if (nds->m_op == NDR_M_OP_MARSHALL)
72 rc = NDR_DRC_FAULT_ENCODE_FAILED;
73 else
74 rc = NDR_DRC_FAULT_DECODE_FAILED;
75 break;
78 return (rc);
81 ndr_buf_t *
82 ndr_buf_init(ndr_typeinfo_t *ti)
84 ndr_buf_t *nbuf;
86 if ((nbuf = calloc(1, sizeof (ndr_buf_t))) == NULL)
87 return (NULL);
89 if ((nbuf->nb_heap = ndr_heap_create()) == NULL) {
90 free(nbuf);
91 return (NULL);
94 nbuf->nb_ti = ti;
95 nbuf->nb_magic = NDR_BUF_MAGIC;
96 return (nbuf);
99 void
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);
106 nbuf->nb_magic = 0;
107 free(nbuf);
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:
116 * pac_info_t info;
118 * if ((nbuf = ndr_buf_init(&TYPEINFO(ndr_pac)) != NULL) {
119 * rc = ndr_decode_buf(nbuf, opnum, data, datalen, &info);
120 * ...
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;
131 int rc;
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;
139 else
140 pdu_size_hint = datalen;
142 rc = nds_initialize(&nbuf->nb_nds, pdu_size_hint, NDR_MODE_BUF_DECODE,
143 nbuf->nb_heap);
144 if (NDR_DRC_IS_FAULT(rc))
145 return (rc);
147 bcopy(data, nbuf->nb_nds.pdu_base_addr, datalen);
149 switch (hdr_type) {
150 case NDR_PTYPE_COMMON:
151 rc = ndr_decode_hdr_common(&nbuf->nb_nds, &hdr);
152 if (NDR_DRC_IS_FAULT(rc))
153 return (rc);
155 if (!NDR_IS_SINGLE_FRAG(hdr.pfc_flags))
156 return (NDR_DRC_FAULT_DECODE_FAILED);
157 break;
159 case NDR_PTYPE_PAC:
160 rc = ndr_decode_pac_hdr(&nbuf->nb_nds, &pac_hdr);
161 if (NDR_DRC_IS_FAULT(rc))
162 return (rc);
164 if (pac_hdr.common_hdr.hdrlen != sizeof (ndr_serialtype1_hdr_t))
165 return (NDR_DRC_FAULT_DECODE_FAILED);
166 break;
168 default:
169 return (NDR_ERR_UNIMPLEMENTED);
172 rc = ndr_encode_decode_common(&nbuf->nb_nds, opnum, nbuf->nb_ti,
173 result);
174 return (rc);
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;
184 int rc;
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;
202 int rc;
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;
220 int rc;
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;
238 int rc;
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;
254 int rc;
256 rc = ndr_decode_hdr_common(nds, hdr);
257 if (NDR_DRC_IS_FAULT(rc))
258 return (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;
267 return (NDR_DRC_OK);
270 static int
271 ndr_decode_hdr_common(ndr_stream_t *nds, ndr_common_header_t *hdr)
273 int ptype;
274 int rc;
275 int charset;
276 int byte_order;
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);
285 if (!rc)
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);
292 if (!rc)
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;
310 ptype = hdr->ptype;
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));
321 static int
322 ndr_decode_pac_hdr(ndr_stream_t *nds, ndr_pac_hdr_t *hdr)
324 int rc;
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);
333 if (!rc)
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);
340 if (!rc)
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.
351 nds->swap =
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
363 * fragment headers.
365 void
366 ndr_decode_frag_hdr(ndr_stream_t *nds, ndr_common_header_t *hdr)
368 ndr_common_header_t *tmp;
369 uint8_t *pdu;
370 int byte_order;
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,
386 sizeof (WORD));
387 nds_bswap(&tmp->auth_length, &hdr->auth_length,
388 sizeof (WORD));
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:
398 * |<--- frag --->|
399 * +-----+--------+-----+--------+-----+---------+-----+
400 * | hdr | data | hdr | data | hdr | data | ... |
401 * +-----+--------+-----+--------+-----+---------+-----+
402 * <----
404 * NDR stream on return:
406 * +-----+----------------+-----+---------+-----+
407 * | hdr | data | hdr | data | ... |
408 * +-----+----------------+-----+---------+-----+
410 void
411 ndr_remove_frag_hdr(ndr_stream_t *nds)
413 char *hdr;
414 char *data;
415 int nbytes;
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;
425 void
426 ndr_show_hdr(ndr_common_header_t *hdr)
428 char *fragtype;
430 if (hdr == NULL) {
431 ndo_printf(NULL, NULL, "ndr hdr: <null>");
432 return;
435 if (NDR_IS_SINGLE_FRAG(hdr->pfc_flags))
436 fragtype = "single";
437 else if (NDR_IS_FIRST_FRAG(hdr->pfc_flags))
438 fragtype = "first";
439 else if (NDR_IS_LAST_FRAG(hdr->pfc_flags))
440 fragtype = "last";
441 else
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;
455 int ptype;
456 int rc;
458 if (nds->m_op != NDR_M_OP_MARSHALL)
459 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH);
461 ptype = hdr->ptype;
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
476 * IDL/NDR rules.
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 = {
484 1, /* NDR version */
485 3, /* alignment */
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 */
495 * [_no_reorder]
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;
503 ndr_ref_t myref;
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 */
518 offset = 24UL;
520 switch (nds->m_op) {
521 case NDR_M_OP_MARSHALL:
522 val->sec_addr.length =
523 strlen((char *)val->sec_addr.port_spec) + 1;
524 break;
526 case NDR_M_OP_UNMARSHALL:
527 break;
529 default:
530 NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
531 return (0);
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);
538 offset += 2;
539 offset += val->sec_addr.length;
540 offset += NDR_ALIGN4(offset);
542 NDR_MEMBER(_ndr_p_result_list, p_result_list, offset);
543 return (1);
547 * Assume a single presentation context element in the result list.
549 unsigned
550 ndr_bind_ack_hdr_size(ndr_xa_t *mxa)
552 ndr_bind_ack_hdr_t *bahdr = &mxa->send_hdr.bind_ack_hdr;
553 unsigned offset;
554 unsigned length;
556 /* port any is the conformant culprit */
557 offset = 24UL;
559 length = strlen((char *)bahdr->sec_addr.port_spec) + 1;
561 offset += 2;
562 offset += length;
563 offset += NDR_ALIGN4(offset);
564 offset += sizeof (ndr_p_result_list_t);
565 return (offset);
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 = {
576 1, /* NDR version */
577 3, /* alignment */
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 */
587 * [_no_reorder]
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;
595 ndr_ref_t myref;
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 */
611 switch (nds->m_op) {
612 case NDR_M_OP_MARSHALL:
613 val->sec_addr.length = 0;
614 break;
616 case NDR_M_OP_UNMARSHALL:
617 break;
619 default:
620 NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID);
621 return (0);
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);
632 return (1);
636 * Assume a single presentation context element in the result list.
638 unsigned
639 ndr_alter_context_rsp_hdr_size(void)
641 unsigned offset;
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);
647 return (offset);