xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c (revision 8334:5f1c6a3b0fad)
15772Sas200622 /*
25772Sas200622  * CDDL HEADER START
35772Sas200622  *
45772Sas200622  * The contents of this file are subject to the terms of the
55772Sas200622  * Common Development and Distribution License (the "License").
65772Sas200622  * You may not use this file except in compliance with the License.
75772Sas200622  *
85772Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622  * or http://www.opensolaris.org/os/licensing.
105772Sas200622  * See the License for the specific language governing permissions
115772Sas200622  * and limitations under the License.
125772Sas200622  *
135772Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622  * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622  *
195772Sas200622  * CDDL HEADER END
205772Sas200622  */
215772Sas200622 /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235772Sas200622  * Use is subject to license terms.
245772Sas200622  */
255772Sas200622 
265772Sas200622 /*
275772Sas200622  * Network Data Representation (NDR) is a compatible subset of the DCE RPC
285772Sas200622  * and MSRPC NDR.  NDR is used to move parameters consisting of
295772Sas200622  * complicated trees of data constructs between an RPC client and server.
305772Sas200622  */
315772Sas200622 
325772Sas200622 #include <sys/byteorder.h>
335772Sas200622 #include <strings.h>
345772Sas200622 #include <assert.h>
355772Sas200622 #include <string.h>
365772Sas200622 #include <stdlib.h>
375772Sas200622 
385772Sas200622 #include <smbsrv/libsmb.h>
395772Sas200622 #include <smbsrv/string.h>
40*8334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
415772Sas200622 
425772Sas200622 #define	NDR_STRING_MAX		256
435772Sas200622 
445772Sas200622 #define	NDR_IS_UNION(T)	\
455772Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
465772Sas200622 #define	NDR_IS_STRING(T)	\
475772Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
485772Sas200622 
49*8334SJose.Borrego@Sun.COM extern ndr_typeinfo_t ndt_s_wchar;
505772Sas200622 
515772Sas200622 /*
525772Sas200622  * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
535772Sas200622  *
545772Sas200622  * Each parameter (call arguments and return values) is a TOP-MOST item.
555772Sas200622  * A TOP-MOST item consists of one or more OUTER items.  An OUTER item
565772Sas200622  * consists of one or more INNER items.  There are important differences
575772Sas200622  * between each kind, which, primarily, have to do with the allocation
585772Sas200622  * of memory to contain data structures and the order of processing.
595772Sas200622  *
605772Sas200622  * This is most easily demonstrated with a short example.
615772Sas200622  * Consider these structures:
625772Sas200622  *
635772Sas200622  *	struct top_param {
645772Sas200622  *		long		level;
655772Sas200622  *		struct list *	head;
665772Sas200622  *		long		count;
675772Sas200622  *	};
685772Sas200622  *
695772Sas200622  *	struct list {
705772Sas200622  *		struct list *	next;
715772Sas200622  *		char *		str; // a string
725772Sas200622  *	};
735772Sas200622  *
745772Sas200622  * Now, consider an instance tree like this:
755772Sas200622  *
765772Sas200622  *	+---------+       +-------+       +-------+
775772Sas200622  *	|top_param|  +--->|list #1|  +--->|list #2|
785772Sas200622  *	+---------+  |    +-------+  |    +-------+
795772Sas200622  *	| level   |  |    | next ----+    | next --->(NULL)
805772Sas200622  *	| head   ----+    | str  -->"foo" | str  -->"bar"
815772Sas200622  *	| count   |       | flag  |       | flag  |
825772Sas200622  *	+---------+       +-------+       +-------+
835772Sas200622  *
845772Sas200622  * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
855772Sas200622  * The vertical bars (|) indicate OUTER construct boundaries.
865772Sas200622  *
875772Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
885772Sas200622  *   |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
895772Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
905772Sas200622  *   level |<----------------------- head -------------------------->|count
915772Sas200622  *   TOP    TOP                                                       TOP
925772Sas200622  *
935772Sas200622  * Here's what to notice:
945772Sas200622  *
955772Sas200622  * - The members of the TOP-MOST construct are scattered through the Stub
965772Sas200622  *   Data in the order they occur.  This example shows a TOP-MOST construct
975772Sas200622  *   consisting of atomic types (pointers and integers).  A construct
985772Sas200622  *   (struct) within the TOP-MOST construct would be contiguous and not
995772Sas200622  *   scattered.
1005772Sas200622  *
1015772Sas200622  * - The members of OUTER constructs are contiguous, which allows for
1025772Sas200622  *   non-copied relocated (fixed-up) data structures at the packet's
1035772Sas200622  *   destination.  We don't do fix-ups here.  The pointers within the
1045772Sas200622  *   OUTER constructs are processed depth-first in the order that they
1055772Sas200622  *   occur.  If they were processed breadth first, the sequence would
1065772Sas200622  *   be #1,"foo",#2,"bar".  This is tricky because OUTER constructs may
1075772Sas200622  *   be variable length, and pointers are often encountered before the
1085772Sas200622  *   size(s) is known.
1095772Sas200622  *
1105772Sas200622  * - The INNER constructs are simply the members of an OUTER construct.
1115772Sas200622  *
1125772Sas200622  * For comparison, consider how ONC RPC would handle the same tree of
1135772Sas200622  * data.  ONC requires very little buffering, while DCE requires enough
1145772Sas200622  * buffer space for the entire message.  ONC does atom-by-atom depth-first
1155772Sas200622  * (de)serialization and copy, while DCE allows for constructs to be
1165772Sas200622  * "fixed-up" (relocated) in place at the destination.  The packet data
1175772Sas200622  * for the same tree processed by ONC RPC would look like this:
1185772Sas200622  *
1195772Sas200622  *   +---------------------------------------------------------------------+
1205772Sas200622  *   |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
1215772Sas200622  *   +---------------------------------------------------------------------+
1225772Sas200622  *   TOP    #1      #2      #2     bar   #2      #1     foo   #1      TOP
1235772Sas200622  *
1245772Sas200622  * More details about each TOP-MOST, OUTER, and INNER constructs appear
1255772Sas200622  * throughout this source file near where such constructs are processed.
1265772Sas200622  *
1275772Sas200622  * NDR_REFERENCE
1285772Sas200622  *
129*8334SJose.Borrego@Sun.COM  * The primary object for NDR is the ndr_ref_t.
1305772Sas200622  *
131*8334SJose.Borrego@Sun.COM  * An ndr reference indicates the local datum (i.e. native "C" data
1325772Sas200622  * format), and the element within the Stub Data (contained within the
133*8334SJose.Borrego@Sun.COM  * RPC PDU (protocol data unit).  An ndr reference also indicates,
1345772Sas200622  * largely as a debugging aid, something about the type of the
1355772Sas200622  * element/datum, and the enclosing construct for the element. The
136*8334SJose.Borrego@Sun.COM  * ndr reference's are typically allocated on the stack as locals,
137*8334SJose.Borrego@Sun.COM  * and the chain of ndr-reference.enclosing references is in reverse
1385772Sas200622  * order of the call graph.
1395772Sas200622  *
140*8334SJose.Borrego@Sun.COM  * The ndr-reference.datum is a pointer to the local memory that
141*8334SJose.Borrego@Sun.COM  * contains/receives the value. The ndr-reference.pdu_offset indicates
1425772Sas200622  * where in the Stub Data the value is to be stored/retrieved.
1435772Sas200622  *
144*8334SJose.Borrego@Sun.COM  * The ndr-reference also contains various parameters to the NDR
145*8334SJose.Borrego@Sun.COM  * process, such as ndr-reference.size_is, which indicates the size
146*8334SJose.Borrego@Sun.COM  * of variable length data, or ndr-reference.switch_is, which
1475772Sas200622  * indicates the arm of a union to use.
1485772Sas200622  *
1495772Sas200622  * QUEUE OF OUTER REFERENCES
1505772Sas200622  *
1515772Sas200622  * Some OUTER constructs are variable size.  Sometimes (often) we don't
1525772Sas200622  * know the size of the OUTER construct until after pointers have been
1535772Sas200622  * encountered. Hence, we can not begin processing the referent of the
1545772Sas200622  * pointer until after the referring OUTER construct is completely
1555772Sas200622  * processed, i.e. we don't know where to find/put the referent in the
1565772Sas200622  * Stub Data until we know the size of all its predecessors.
1575772Sas200622  *
1585772Sas200622  * This is managed using the queue of OUTER references.  The queue is
159*8334SJose.Borrego@Sun.COM  * anchored in ndr_stream.outer_queue_head.  At any time,
160*8334SJose.Borrego@Sun.COM  * ndr_stream.outer_queue_tailp indicates where to put the
161*8334SJose.Borrego@Sun.COM  * ndr-reference for the next encountered pointer.
1625772Sas200622  *
1635772Sas200622  * Refer to the example above as we illustrate the queue here.  In these
1645772Sas200622  * illustrations, the queue entries are not the data structures themselves.
165*8334SJose.Borrego@Sun.COM  * Rather, they are ndr-reference entries which **refer** to the data
1665772Sas200622  * structures in both the PDU and local memory.
1675772Sas200622  *
1685772Sas200622  * During some point in the processing, the queue looks like this:
1695772Sas200622  *
1705772Sas200622  *   outer_current -------v
1715772Sas200622  *   outer_queue_head --> list#1 --0
1725772Sas200622  *   outer_queue_tailp ---------&
1735772Sas200622  *
1745772Sas200622  * When the pointer #1.next is encountered, and entry is added to the
1755772Sas200622  * queue,
1765772Sas200622  *
1775772Sas200622  *   outer_current -------v
1785772Sas200622  *   outer_queue_head --> list#1 --> list#2 --0
1795772Sas200622  *   outer_queue_tailp --------------------&
1805772Sas200622  *
1815772Sas200622  * and the members of #1 continue to be processed, which encounters
1825772Sas200622  * #1.str:
1835772Sas200622  *
1845772Sas200622  *   outer_current -------v
1855772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
1865772Sas200622  *   outer_queue_tailp ------------------------------&
1875772Sas200622  *
188*8334SJose.Borrego@Sun.COM  * Upon the completion of list#1, the processing continues by moving to
189*8334SJose.Borrego@Sun.COM  * ndr_stream.outer_current->next, and the tail is set to this outer member:
1905772Sas200622  *
1915772Sas200622  *   outer_current ------------------v
1925772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
1935772Sas200622  *   outer_queue_tailp --------------------&
1945772Sas200622  *
1955772Sas200622  * Space for list#2 is allocated, either in the Stub Data or of local
1965772Sas200622  * memory.  When #2.next is encountered, it is found to be the null
1975772Sas200622  * pointer and no reference is added to the queue.  When #2.str is
1985772Sas200622  * encountered, it is found to be valid, and a reference is added:
1995772Sas200622  *
2005772Sas200622  *   outer_current ------------------v
2015772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
2025772Sas200622  *   outer_queue_tailp ------------------------------&
2035772Sas200622  *
2045772Sas200622  * Processing continues in a similar fashion with the string "bar",
2055772Sas200622  * which is variable-length.  At this point, memory for "bar" may be
2065772Sas200622  * malloc()ed during NDR_M_OP_UNMARSHALL:
2075772Sas200622  *
2085772Sas200622  *   outer_current -----------------------------v
2095772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
2105772Sas200622  *   outer_queue_tailp ------------------------------&
2115772Sas200622  *
2125772Sas200622  * And finishes on string "foo".  Notice that because "bar" is a
2135772Sas200622  * variable length string, and we don't know the PDU offset for "foo"
2145772Sas200622  * until we reach this point.
2155772Sas200622  *
2165772Sas200622  * When the queue is drained (current->next==0), processing continues
2175772Sas200622  * with the next TOP-MOST member.
2185772Sas200622  *
2195772Sas200622  * The queue of OUTER constructs manages the variable-length semantics
2205772Sas200622  * of OUTER constructs and satisfies the depth-first requirement.
2215772Sas200622  * We allow the queue to linger until the entire TOP-MOST structure is
2225772Sas200622  * processed as an aid to debugging.
2235772Sas200622  */
2245772Sas200622 
225*8334SJose.Borrego@Sun.COM static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
226*8334SJose.Borrego@Sun.COM extern int ndr__ulong(ndr_ref_t *);
2275772Sas200622 
2285772Sas200622 /*
2295772Sas200622  * TOP-MOST ELEMENTS
2305772Sas200622  *
2315772Sas200622  * This is fundamentally the first OUTER construct of the parameter,
2325772Sas200622  * possibly followed by more OUTER constructs due to pointers.  The
2335772Sas200622  * datum (local memory) for TOP-MOST constructs (structs) is allocated
2345772Sas200622  * by the caller of NDR.
2355772Sas200622  *
2365772Sas200622  * After the element is transferred, the outer_queue is drained.
2375772Sas200622  *
2385772Sas200622  * All we have to do is add an entry to the outer_queue for this
2395772Sas200622  * top-most member, and commence the outer_queue processing.
2405772Sas200622  */
2415772Sas200622 int
242*8334SJose.Borrego@Sun.COM ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
2435772Sas200622 {
244*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
2455772Sas200622 
2465772Sas200622 	bzero(&myref, sizeof (myref));
247*8334SJose.Borrego@Sun.COM 	myref.stream = nds;
2485772Sas200622 	myref.datum = datum;
2495772Sas200622 	myref.name = "PROCESS";
2505772Sas200622 	myref.ti = ti;
2515772Sas200622 
252*8334SJose.Borrego@Sun.COM 	return (ndr_topmost(&myref));
2535772Sas200622 }
2545772Sas200622 
2555772Sas200622 int
256*8334SJose.Borrego@Sun.COM ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
2575772Sas200622 {
258*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
2595772Sas200622 
2605772Sas200622 	bzero(&myref, sizeof (myref));
261*8334SJose.Borrego@Sun.COM 	myref.stream = nds;
2625772Sas200622 	myref.datum = datum;
2635772Sas200622 	myref.name = "OPERATION";
2645772Sas200622 	myref.ti = ti;
2655772Sas200622 	myref.inner_flags = NDR_F_SWITCH_IS;
2665772Sas200622 	myref.switch_is = opnum;
2675772Sas200622 
2685772Sas200622 	if (ti->type_flags != NDR_F_INTERFACE) {
2695772Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
2705772Sas200622 		return (0);
2715772Sas200622 	}
2725772Sas200622 
2735772Sas200622 	return ((*ti->ndr_func)(&myref));
2745772Sas200622 }
2755772Sas200622 
2765772Sas200622 int
277*8334SJose.Borrego@Sun.COM ndr_params(ndr_ref_t *params_ref)
2785772Sas200622 {
279*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t *ti = params_ref->ti;
2805772Sas200622 
2815772Sas200622 	if (ti->type_flags == NDR_F_OPERATION)
2825772Sas200622 		return (*ti->ndr_func) (params_ref);
2835772Sas200622 	else
284*8334SJose.Borrego@Sun.COM 		return (ndr_topmost(params_ref));
2855772Sas200622 }
2865772Sas200622 
2875772Sas200622 int
288*8334SJose.Borrego@Sun.COM ndr_topmost(ndr_ref_t *top_ref)
2895772Sas200622 {
290*8334SJose.Borrego@Sun.COM 	ndr_stream_t *nds;
291*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t *ti;
292*8334SJose.Borrego@Sun.COM 	ndr_ref_t *outer_ref = 0;
2935772Sas200622 	int	is_varlen;
2945772Sas200622 	int	is_string;
2955772Sas200622 	int	error;
2965772Sas200622 	int	rc;
2975772Sas200622 	unsigned n_fixed;
2985772Sas200622 	int	params;
2995772Sas200622 
3005772Sas200622 	assert(top_ref);
3015772Sas200622 	assert(top_ref->stream);
3025772Sas200622 	assert(top_ref->ti);
3035772Sas200622 
304*8334SJose.Borrego@Sun.COM 	nds = top_ref->stream;
3055772Sas200622 	ti = top_ref->ti;
3065772Sas200622 
3075772Sas200622 	is_varlen = ti->pdu_size_variable_part;
3085772Sas200622 	is_string = NDR_IS_STRING(ti);
3095772Sas200622 
310*8334SJose.Borrego@Sun.COM 	assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
311*8334SJose.Borrego@Sun.COM 	assert(!nds->outer_current);
3125772Sas200622 
3135772Sas200622 	params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
3145772Sas200622 
3155772Sas200622 	switch (params) {
3165772Sas200622 	case NDR_F_NONE:
3175772Sas200622 	case NDR_F_SWITCH_IS:
3185772Sas200622 		if (is_string || is_varlen) {
3195772Sas200622 			error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
3205772Sas200622 			NDR_SET_ERROR(outer_ref, error);
3215772Sas200622 			return (0);
3225772Sas200622 		}
3235772Sas200622 		n_fixed = ti->pdu_size_fixed_part;
3245772Sas200622 		break;
3255772Sas200622 
3265772Sas200622 	case NDR_F_SIZE_IS:
3275772Sas200622 		error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
3285772Sas200622 		NDR_SET_ERROR(outer_ref, error);
3295772Sas200622 		return (0);
3305772Sas200622 
3315772Sas200622 	case NDR_F_DIMENSION_IS:
3325772Sas200622 		if (is_varlen) {
3335772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
3345772Sas200622 			NDR_SET_ERROR(outer_ref, error);
3355772Sas200622 			return (0);
3365772Sas200622 		}
3375772Sas200622 		n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
3385772Sas200622 		break;
3395772Sas200622 
3405772Sas200622 	case NDR_F_IS_POINTER:
3415772Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
3425772Sas200622 		n_fixed = 4;
3435772Sas200622 		break;
3445772Sas200622 
3455772Sas200622 	case NDR_F_IS_REFERENCE:
3465772Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
3475772Sas200622 		n_fixed = 0;
3485772Sas200622 		break;
3495772Sas200622 
3505772Sas200622 	default:
3515772Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
3525772Sas200622 		NDR_SET_ERROR(outer_ref, error);
3535772Sas200622 		return (0);
3545772Sas200622 	}
3555772Sas200622 
356*8334SJose.Borrego@Sun.COM 	outer_ref = ndr_enter_outer_queue(top_ref);
3575772Sas200622 	if (!outer_ref)
3585772Sas200622 		return (0);	/* error already set */
3595772Sas200622 
3605772Sas200622 	/*
3615772Sas200622 	 * Hand-craft the first OUTER construct and directly call
362*8334SJose.Borrego@Sun.COM 	 * ndr_inner(). Then, run the outer_queue. We do this
363*8334SJose.Borrego@Sun.COM 	 * because ndr_outer() wants to malloc() memory for
3645772Sas200622 	 * the construct, and we already have the memory.
3655772Sas200622 	 */
3665772Sas200622 
3675772Sas200622 	/* move the flags, etc, around again, undoes enter_outer_queue() */
3685772Sas200622 	outer_ref->inner_flags = top_ref->inner_flags;
3695772Sas200622 	outer_ref->outer_flags = 0;
3705772Sas200622 	outer_ref->datum = top_ref->datum;
3715772Sas200622 
3725772Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
373*8334SJose.Borrego@Sun.COM 	if (!ndr_outer_align(outer_ref))
3745772Sas200622 		return (0);		/* error already set */
3755772Sas200622 
3765772Sas200622 	/* Regardless of what it is, this is where it starts */
377*8334SJose.Borrego@Sun.COM 	outer_ref->pdu_offset = nds->pdu_scan_offset;
3785772Sas200622 
379*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_fixed);
3805772Sas200622 	if (!rc)
3815772Sas200622 		return (0);		/* error already set */
3825772Sas200622 
3835772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
3845772Sas200622 
3855772Sas200622 	/* set-up outer_current, as though run_outer_queue() was doing it */
386*8334SJose.Borrego@Sun.COM 	nds->outer_current = outer_ref;
387*8334SJose.Borrego@Sun.COM 	nds->outer_queue_tailp = &nds->outer_current->next;
388*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
3895772Sas200622 
3905772Sas200622 	/* do the topmost member */
391*8334SJose.Borrego@Sun.COM 	rc = ndr_inner(outer_ref);
3925772Sas200622 	if (!rc)
3935772Sas200622 		return (0);		/* error already set */
3945772Sas200622 
395*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
3965772Sas200622 
3975772Sas200622 	/* advance, as though run_outer_queue() was doing it */
398*8334SJose.Borrego@Sun.COM 	nds->outer_current = nds->outer_current->next;
399*8334SJose.Borrego@Sun.COM 	return (ndr_run_outer_queue(nds));
4005772Sas200622 }
4015772Sas200622 
402*8334SJose.Borrego@Sun.COM static ndr_ref_t *
403*8334SJose.Borrego@Sun.COM ndr_enter_outer_queue(ndr_ref_t *arg_ref)
4045772Sas200622 {
405*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = arg_ref->stream;
406*8334SJose.Borrego@Sun.COM 	ndr_ref_t	*outer_ref;
4075772Sas200622 
4085772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
409*8334SJose.Borrego@Sun.COM 	outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
4105772Sas200622 	if (!outer_ref) {
4115772Sas200622 		NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
4125772Sas200622 		return (0);
4135772Sas200622 	}
4145772Sas200622 
4155772Sas200622 	*outer_ref = *arg_ref;
4165772Sas200622 
4175772Sas200622 	/* move advice in inner_flags to outer_flags */
4185772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
4195772Sas200622 	outer_ref->inner_flags = 0;
420*8334SJose.Borrego@Sun.COM 	outer_ref->enclosing = nds->outer_current;
4215772Sas200622 	outer_ref->backptr = 0;
4225772Sas200622 	outer_ref->datum = 0;
4235772Sas200622 
424*8334SJose.Borrego@Sun.COM 	assert(nds->outer_queue_tailp);
4255772Sas200622 
426*8334SJose.Borrego@Sun.COM 	outer_ref->next = *nds->outer_queue_tailp;
427*8334SJose.Borrego@Sun.COM 	*nds->outer_queue_tailp = outer_ref;
428*8334SJose.Borrego@Sun.COM 	nds->outer_queue_tailp = &outer_ref->next;
4295772Sas200622 	return (outer_ref);
4305772Sas200622 }
4315772Sas200622 
4325772Sas200622 int
433*8334SJose.Borrego@Sun.COM ndr_run_outer_queue(ndr_stream_t *nds)
4345772Sas200622 {
435*8334SJose.Borrego@Sun.COM 	while (nds->outer_current) {
436*8334SJose.Borrego@Sun.COM 		nds->outer_queue_tailp = &nds->outer_current->next;
4375772Sas200622 
438*8334SJose.Borrego@Sun.COM 		if (!ndr_outer(nds->outer_current))
4395772Sas200622 			return (0);
4405772Sas200622 
441*8334SJose.Borrego@Sun.COM 		nds->outer_current = nds->outer_current->next;
4425772Sas200622 	}
4435772Sas200622 
4445772Sas200622 	return (1);
4455772Sas200622 }
4465772Sas200622 
4475772Sas200622 /*
4485772Sas200622  * OUTER CONSTRUCTS
4495772Sas200622  *
4505772Sas200622  * OUTER constructs are where the real work is, which stems from the
4515772Sas200622  * variable-length potential.
4525772Sas200622  *
4535772Sas200622  * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
4545772Sas200622  *
4555772Sas200622  * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
4565772Sas200622  * VARYING, and VARYING/CONFORMANT.
4575772Sas200622  *
4585772Sas200622  * What makes this so tough is that the variable-length array may be well
4595772Sas200622  * encapsulated within the outer construct.  Further, because DCE(MS)/RPC
4605772Sas200622  * tries to keep the constructs contiguous in the data stream, the sizing
4615772Sas200622  * information precedes the entire OUTER construct.  The sizing information
4625772Sas200622  * must be used at the appropriate time, which can be after many, many,
4635772Sas200622  * many fixed-length elements.  During IDL type analysis, we know in
4645772Sas200622  * advance constructs that encapsulate variable-length constructs.  So,
4655772Sas200622  * we know when we have a sizing header and when we don't.  The actual
4665772Sas200622  * semantics of the header are largely deferred.
4675772Sas200622  *
4685772Sas200622  * Currently, VARYING constructs are not implemented but they are described
4695772Sas200622  * here in case they have to be implemented in the future.  Similarly,
4705772Sas200622  * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
4715772Sas200622  * not implemented.  Only one-dimensional, variable-length arrays are
4725772Sas200622  * supported.
4735772Sas200622  *
4745772Sas200622  * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
4755772Sas200622  *
4765772Sas200622  * All variable-length values are arrays.  These arrays may be embedded
4775772Sas200622  * well within another construct.  However, a variable-length construct
4785772Sas200622  * may ONLY appear as the last member of an enclosing construct.  Example:
4795772Sas200622  *
4805772Sas200622  *	struct credentials {
4815772Sas200622  *		ulong	uid, gid;
4825772Sas200622  *		ulong	n_gids;
4835772Sas200622  *	    [size_is(n_gids)]
4845772Sas200622  *		ulong	gids[*];    // variable-length.
4855772Sas200622  *	};
4865772Sas200622  *
4875772Sas200622  * CONFORMANT constructs have a dynamic size in local memory and in the
4885772Sas200622  * PDU.  The CONFORMANT quality is indicated by the [size_is()] advice.
4895772Sas200622  * CONFORMANT constructs have the following header:
4905772Sas200622  *
4915772Sas200622  *	struct conformant_header {
4925772Sas200622  *		ulong		size_is;
4935772Sas200622  *	};
4945772Sas200622  *
4955772Sas200622  * (Multi-dimensional CONFORMANT arrays have a similar header for each
4965772Sas200622  * dimension - not implemented).
4975772Sas200622  *
4985772Sas200622  * Example CONFORMANT construct:
4995772Sas200622  *
5005772Sas200622  *	struct user {
5015772Sas200622  *		char *			name;
5025772Sas200622  *		struct credentials	cred;	// see above
5035772Sas200622  *	};
5045772Sas200622  *
5055772Sas200622  * Consider the data tree:
5065772Sas200622  *
5075772Sas200622  *    +--------+
5085772Sas200622  *    |  user  |
5095772Sas200622  *    +--------+
5105772Sas200622  *    | name  ----> "fred" (the string is a different OUTER)
5115772Sas200622  *    | uid    |
5125772Sas200622  *    | gid    |
5135772Sas200622  *    | n_gids |    for example, 3
5145772Sas200622  *    | gids[0]|
5155772Sas200622  *    | gids[1]|
5165772Sas200622  *    | gids[2]|
5175772Sas200622  *    +--------+
5185772Sas200622  *
5195772Sas200622  * The OUTER construct in the Stub Data would be:
5205772Sas200622  *
5215772Sas200622  *    +---+---------+---------------------------------------------+
5225772Sas200622  *    |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
5235772Sas200622  *    +---+---------+---------------------------------------------+
5245772Sas200622  *         szing hdr|user |<-------------- user.cred ------------>|
5255772Sas200622  *                  |<--- fixed-size ---->|<----- conformant ---->|
5265772Sas200622  *
5275772Sas200622  * The ndr_typeinfo for struct user will have:
5285772Sas200622  *	pdu_fixed_size_part = 16	four long words (name uid gid n_gids)
5295772Sas200622  *	pdu_variable_size_part = 4	per element, sizeof gids[0]
5305772Sas200622  *
5315772Sas200622  * VARYING CONSTRUCTS -- NOT IMPLEMENTED
5325772Sas200622  *
5335772Sas200622  * VARYING constructs have the following header:
5345772Sas200622  *
5355772Sas200622  *	struct varying_header {
5365772Sas200622  *		ulong		first_is;
5375772Sas200622  *		ulong		length_is;
5385772Sas200622  *	};
5395772Sas200622  *
5405772Sas200622  * This indicates which interval of an array is significant.
5415772Sas200622  * Non-intersecting elements of the array are undefined and usually
5425772Sas200622  * zero-filled.  The first_is parameter for C arrays is always 0 for
5435772Sas200622  * the first element.
5445772Sas200622  *
5455772Sas200622  * N.B. Constructs may contain one CONFORMANT element, which is always
5465772Sas200622  * last, but may contain many VARYING elements, which can be anywhere.
5475772Sas200622  *
5485772Sas200622  * VARYING CONFORMANT constructs have the sizing headers arranged like
5495772Sas200622  * this:
5505772Sas200622  *
5515772Sas200622  *	struct conformant_header	all_conformant[N_CONFORMANT_DIM];
5525772Sas200622  *	struct varying_header		all_varying[N_VARYING_ELEMS_AND_DIMS];
5535772Sas200622  *
5545772Sas200622  * The sizing header is immediately followed by the values for the
5555772Sas200622  * construct.  Again, we don't support more than one dimension and
5565772Sas200622  * we don't support VARYING constructs at this time.
5575772Sas200622  *
5585772Sas200622  * A good example of a VARYING/CONFORMANT data structure is the UNIX
5595772Sas200622  * directory entry:
5605772Sas200622  *
5615772Sas200622  *	struct dirent {
5625772Sas200622  *		ushort		reclen;
5635772Sas200622  *		ushort		namlen;
5645772Sas200622  *		ulong		inum;
5655772Sas200622  *	    [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
5665772Sas200622  *		uchar		name[*];
5675772Sas200622  *	};
5685772Sas200622  *
5695772Sas200622  *
5705772Sas200622  * STRINGS ARE A SPECIAL CASE
5715772Sas200622  *
5725772Sas200622  * Strings are handled specially.  MS/RPC uses VARYING/CONFORMANT structures
5735772Sas200622  * for strings.  This is a simple one-dimensional variable-length array,
5745772Sas200622  * typically with its last element all zeroes.  We handle strings with the
5755772Sas200622  * header:
5765772Sas200622  *
5775772Sas200622  *	struct string_header {
5785772Sas200622  *		ulong		size_is;
5795772Sas200622  *		ulong		first_is;	// always 0
5805772Sas200622  *		ulong		length_is;	// always same as size_is
5815772Sas200622  *	};
5825772Sas200622  *
5835772Sas200622  * If general support for VARYING and VARYING/CONFORMANT mechanisms is
5845772Sas200622  * implemented, we probably won't need the strings special case.
5855772Sas200622  */
5865772Sas200622 int
587*8334SJose.Borrego@Sun.COM ndr_outer(ndr_ref_t *outer_ref)
5885772Sas200622 {
589*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = outer_ref->stream;
590*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t	*ti = outer_ref->ti;
5915772Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
5925772Sas200622 	int	is_union = NDR_IS_UNION(ti);
5935772Sas200622 	int	is_string = NDR_IS_STRING(ti);
5945772Sas200622 	int	error = NDR_ERR_OUTER_PARAMS_BAD;
5955772Sas200622 	int	params;
5965772Sas200622 
5975772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
5985772Sas200622 
5995772Sas200622 	NDR_TATTLE(outer_ref, "--OUTER--");
6005772Sas200622 
6015772Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
602*8334SJose.Borrego@Sun.COM 	if (!ndr_outer_align(outer_ref))
6035772Sas200622 		return (0);		/* error already set */
6045772Sas200622 
6055772Sas200622 	/* Regardless of what it is, this is where it starts */
606*8334SJose.Borrego@Sun.COM 	outer_ref->pdu_offset = nds->pdu_scan_offset;
6075772Sas200622 
6085772Sas200622 	if (is_union) {
6095772Sas200622 		error = NDR_ERR_OUTER_UNION_ILLEGAL;
6105772Sas200622 		NDR_SET_ERROR(outer_ref, error);
6115772Sas200622 		return (0);
6125772Sas200622 	}
6135772Sas200622 
6145772Sas200622 	switch (params) {
6155772Sas200622 	case NDR_F_NONE:
6165772Sas200622 		if (is_string)
617*8334SJose.Borrego@Sun.COM 			return (ndr_outer_string(outer_ref));
6185772Sas200622 		if (is_varlen)
619*8334SJose.Borrego@Sun.COM 			return (ndr_outer_conformant_construct(outer_ref));
6205772Sas200622 
621*8334SJose.Borrego@Sun.COM 		return (ndr_outer_fixed(outer_ref));
6225772Sas200622 		break;
6235772Sas200622 
6245772Sas200622 	case NDR_F_SIZE_IS:
6255772Sas200622 	case NDR_F_DIMENSION_IS:
6265772Sas200622 		if (is_varlen) {
6275772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
6285772Sas200622 			break;
6295772Sas200622 		}
6305772Sas200622 
6315772Sas200622 		if (params == NDR_F_SIZE_IS)
632*8334SJose.Borrego@Sun.COM 			return (ndr_outer_conformant_array(outer_ref));
6335772Sas200622 		else
634*8334SJose.Borrego@Sun.COM 			return (ndr_outer_fixed_array(outer_ref));
6355772Sas200622 		break;
6365772Sas200622 
6375772Sas200622 	default:
6385772Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
6395772Sas200622 		break;
6405772Sas200622 	}
6415772Sas200622 
6425772Sas200622 	/*
6435772Sas200622 	 * If we get here, something is wrong. Most likely,
6445772Sas200622 	 * the params flags do not match.
6455772Sas200622 	 */
6465772Sas200622 	NDR_SET_ERROR(outer_ref, error);
6475772Sas200622 	return (0);
6485772Sas200622 }
6495772Sas200622 
6505772Sas200622 int
651*8334SJose.Borrego@Sun.COM ndr_outer_fixed(ndr_ref_t *outer_ref)
6525772Sas200622 {
653*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = outer_ref->stream;
654*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t	*ti = outer_ref->ti;
655*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
6565772Sas200622 	char 		*valp = NULL;
6575772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
6585772Sas200622 	int		is_union = NDR_IS_UNION(ti);
6595772Sas200622 	int		is_string = NDR_IS_STRING(ti);
6605772Sas200622 	int		rc;
6615772Sas200622 	unsigned	n_hdr;
6625772Sas200622 	unsigned	n_fixed;
6635772Sas200622 	unsigned	n_variable;
6645772Sas200622 	unsigned	n_alloc;
6655772Sas200622 	unsigned	n_pdu_total;
6665772Sas200622 	int		params;
6675772Sas200622 
6685772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
6695772Sas200622 
6705772Sas200622 	assert(!is_varlen && !is_string && !is_union);
6715772Sas200622 	assert(params == NDR_F_NONE);
6725772Sas200622 
6735772Sas200622 	/* no header for this */
6745772Sas200622 	n_hdr = 0;
6755772Sas200622 
6765772Sas200622 	/* fixed part -- exactly one of these */
6775772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
6785772Sas200622 	assert(n_fixed > 0);
6795772Sas200622 
6805772Sas200622 	/* variable part -- exactly none of these */
6815772Sas200622 	n_variable = 0;
6825772Sas200622 
6835772Sas200622 	/* sum them up to determine the PDU space required */
6845772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
6855772Sas200622 
6865772Sas200622 	/* similar sum to determine how much local memory is required */
6875772Sas200622 	n_alloc = n_fixed + n_variable;
6885772Sas200622 
689*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
6905772Sas200622 	if (!rc)
6915772Sas200622 		return (rc);		/* error already set */
6925772Sas200622 
693*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
6945772Sas200622 	case NDR_M_OP_MARSHALL:
6955772Sas200622 		valp = outer_ref->datum;
6965772Sas200622 		assert(valp);
6975772Sas200622 		if (outer_ref->backptr) {
6985772Sas200622 			assert(valp == *outer_ref->backptr);
6995772Sas200622 		}
7005772Sas200622 		break;
7015772Sas200622 
7025772Sas200622 	case NDR_M_OP_UNMARSHALL:
703*8334SJose.Borrego@Sun.COM 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
7045772Sas200622 		if (!valp) {
7055772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
7065772Sas200622 			return (0);
7075772Sas200622 		}
7085772Sas200622 		if (outer_ref->backptr)
7095772Sas200622 			*outer_ref->backptr = valp;
7105772Sas200622 		outer_ref->datum = valp;
7115772Sas200622 		break;
7125772Sas200622 
7135772Sas200622 	default:
7145772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
7155772Sas200622 		return (0);
7165772Sas200622 	}
7175772Sas200622 
7185772Sas200622 	bzero(&myref, sizeof (myref));
719*8334SJose.Borrego@Sun.COM 	myref.stream = nds;
7205772Sas200622 	myref.enclosing = outer_ref;
7215772Sas200622 	myref.ti = outer_ref->ti;
7225772Sas200622 	myref.datum = outer_ref->datum;
7235772Sas200622 	myref.name = "FIXED-VALUE";
7245772Sas200622 	myref.outer_flags = NDR_F_NONE;
7255772Sas200622 	myref.inner_flags = NDR_F_NONE;
7265772Sas200622 
7275772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
7285772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
7295772Sas200622 
730*8334SJose.Borrego@Sun.COM 	rc = ndr_inner(&myref);
7315772Sas200622 	if (!rc)
7325772Sas200622 		return (rc);		/* error already set */
7335772Sas200622 
734*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
7355772Sas200622 	return (1);
7365772Sas200622 }
7375772Sas200622 
7385772Sas200622 int
739*8334SJose.Borrego@Sun.COM ndr_outer_fixed_array(ndr_ref_t *outer_ref)
7405772Sas200622 {
741*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = outer_ref->stream;
742*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t	*ti = outer_ref->ti;
743*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
7445772Sas200622 	char 		*valp = NULL;
7455772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
7465772Sas200622 	int		is_union = NDR_IS_UNION(ti);
7475772Sas200622 	int		is_string = NDR_IS_STRING(ti);
7485772Sas200622 	int		rc;
7495772Sas200622 	unsigned	n_hdr;
7505772Sas200622 	unsigned	n_fixed;
7515772Sas200622 	unsigned	n_variable;
7525772Sas200622 	unsigned	n_alloc;
7535772Sas200622 	unsigned	n_pdu_total;
7545772Sas200622 	int		params;
7555772Sas200622 
7565772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
7575772Sas200622 
7585772Sas200622 	assert(!is_varlen && !is_string && !is_union);
7595772Sas200622 	assert(params == NDR_F_DIMENSION_IS);
7605772Sas200622 
7615772Sas200622 	/* no header for this */
7625772Sas200622 	n_hdr = 0;
7635772Sas200622 
7645772Sas200622 	/* fixed part -- exactly dimension_is of these */
7655772Sas200622 	n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
7665772Sas200622 	assert(n_fixed > 0);
7675772Sas200622 
7685772Sas200622 	/* variable part -- exactly none of these */
7695772Sas200622 	n_variable = 0;
7705772Sas200622 
7715772Sas200622 	/* sum them up to determine the PDU space required */
7725772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
7735772Sas200622 
7745772Sas200622 	/* similar sum to determine how much local memory is required */
7755772Sas200622 	n_alloc = n_fixed + n_variable;
7765772Sas200622 
777*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
7785772Sas200622 	if (!rc)
7795772Sas200622 		return (rc);		/* error already set */
7805772Sas200622 
781*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
7825772Sas200622 	case NDR_M_OP_MARSHALL:
7835772Sas200622 		valp = outer_ref->datum;
7845772Sas200622 		assert(valp);
7855772Sas200622 		if (outer_ref->backptr) {
7865772Sas200622 			assert(valp == *outer_ref->backptr);
7875772Sas200622 		}
7885772Sas200622 		break;
7895772Sas200622 
7905772Sas200622 	case NDR_M_OP_UNMARSHALL:
791*8334SJose.Borrego@Sun.COM 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
7925772Sas200622 		if (!valp) {
7935772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
7945772Sas200622 			return (0);
7955772Sas200622 		}
7965772Sas200622 		if (outer_ref->backptr)
7975772Sas200622 			*outer_ref->backptr = valp;
7985772Sas200622 		outer_ref->datum = valp;
7995772Sas200622 		break;
8005772Sas200622 
8015772Sas200622 	default:
8025772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
8035772Sas200622 		return (0);
8045772Sas200622 	}
8055772Sas200622 
8065772Sas200622 	bzero(&myref, sizeof (myref));
807*8334SJose.Borrego@Sun.COM 	myref.stream = nds;
8085772Sas200622 	myref.enclosing = outer_ref;
8095772Sas200622 	myref.ti = outer_ref->ti;
8105772Sas200622 	myref.datum = outer_ref->datum;
8115772Sas200622 	myref.name = "FIXED-ARRAY";
8125772Sas200622 	myref.outer_flags = NDR_F_NONE;
8135772Sas200622 	myref.inner_flags = NDR_F_DIMENSION_IS;
8145772Sas200622 	myref.dimension_is = outer_ref->dimension_is;
8155772Sas200622 
8165772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
8175772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
8185772Sas200622 
819*8334SJose.Borrego@Sun.COM 	rc = ndr_inner(&myref);
8205772Sas200622 	if (!rc)
8215772Sas200622 		return (rc);		/* error already set */
8225772Sas200622 
823*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
8245772Sas200622 	return (1);
8255772Sas200622 }
8265772Sas200622 
8275772Sas200622 int
828*8334SJose.Borrego@Sun.COM ndr_outer_conformant_array(ndr_ref_t *outer_ref)
8295772Sas200622 {
830*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = outer_ref->stream;
831*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t	*ti = outer_ref->ti;
832*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
8335772Sas200622 	char 		*valp = NULL;
8345772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
8355772Sas200622 	int		is_union = NDR_IS_UNION(ti);
8365772Sas200622 	int		is_string = NDR_IS_STRING(ti);
8375772Sas200622 	unsigned long	size_is;
8385772Sas200622 	int		rc;
8395772Sas200622 	unsigned	n_hdr;
8405772Sas200622 	unsigned	n_fixed;
8415772Sas200622 	unsigned	n_variable;
8425772Sas200622 	unsigned	n_alloc;
8435772Sas200622 	unsigned	n_pdu_total;
8445772Sas200622 	int		params;
8455772Sas200622 
8465772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
8475772Sas200622 
8485772Sas200622 	assert(!is_varlen && !is_string && !is_union);
8495772Sas200622 	assert(params == NDR_F_SIZE_IS);
8505772Sas200622 
8515772Sas200622 	/* conformant header for this */
8525772Sas200622 	n_hdr = 4;
8535772Sas200622 
8545772Sas200622 	/* fixed part -- exactly none of these */
8555772Sas200622 	n_fixed = 0;
8565772Sas200622 
8575772Sas200622 	/* variable part -- exactly size_of of these */
8585772Sas200622 	/* notice that it is the **fixed** size of the ti */
8595772Sas200622 	n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
8605772Sas200622 
8615772Sas200622 	/* sum them up to determine the PDU space required */
8625772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
8635772Sas200622 
8645772Sas200622 	/* similar sum to determine how much local memory is required */
8655772Sas200622 	n_alloc = n_fixed + n_variable;
8665772Sas200622 
867*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
8685772Sas200622 	if (!rc)
8695772Sas200622 		return (rc);		/* error already set */
8705772Sas200622 
871*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
8725772Sas200622 	case NDR_M_OP_MARSHALL:
8735772Sas200622 		size_is = outer_ref->size_is;
874*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
8755772Sas200622 		if (!rc)
8765772Sas200622 			return (0);	/* error already set */
8775772Sas200622 
8785772Sas200622 		valp = outer_ref->datum;
8795772Sas200622 		assert(valp);
8805772Sas200622 		if (outer_ref->backptr) {
8815772Sas200622 			assert(valp == *outer_ref->backptr);
8825772Sas200622 		}
8835772Sas200622 		break;
8845772Sas200622 
8855772Sas200622 	case NDR_M_OP_UNMARSHALL:
886*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
8875772Sas200622 		if (!rc)
8885772Sas200622 			return (0);	/* error already set */
8895772Sas200622 
8905772Sas200622 		if (size_is != outer_ref->size_is) {
8915772Sas200622 			NDR_SET_ERROR(outer_ref,
8925772Sas200622 			    NDR_ERR_SIZE_IS_MISMATCH_PDU);
8935772Sas200622 			return (0);
8945772Sas200622 		}
8955772Sas200622 
8966771Sjb150015 		if (size_is > 0) {
897*8334SJose.Borrego@Sun.COM 			valp = NDS_MALLOC(nds, n_alloc, outer_ref);
8986771Sjb150015 			if (!valp) {
8996771Sjb150015 				NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
9006771Sjb150015 				return (0);
9016771Sjb150015 			}
9025772Sas200622 		}
9036771Sjb150015 
9045772Sas200622 		if (outer_ref->backptr)
9055772Sas200622 			*outer_ref->backptr = valp;
9065772Sas200622 		outer_ref->datum = valp;
9075772Sas200622 		break;
9085772Sas200622 
9095772Sas200622 	default:
9105772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
9115772Sas200622 		return (0);
9125772Sas200622 	}
9135772Sas200622 
9145772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
9155772Sas200622 	outer_ref->type_flags = NDR_F_NONE;
9165772Sas200622 	outer_ref->inner_flags = NDR_F_NONE;
9175772Sas200622 
9186771Sjb150015 	if (size_is > 0) {
9196771Sjb150015 		bzero(&myref, sizeof (myref));
920*8334SJose.Borrego@Sun.COM 		myref.stream = nds;
9216771Sjb150015 		myref.enclosing = outer_ref;
9226771Sjb150015 		myref.ti = outer_ref->ti;
9236771Sjb150015 		myref.datum = outer_ref->datum;
9246771Sjb150015 		myref.name = "CONFORMANT-ARRAY";
9256771Sjb150015 		myref.outer_flags = NDR_F_NONE;
9266771Sjb150015 		myref.inner_flags = NDR_F_SIZE_IS;
9276771Sjb150015 		myref.size_is = outer_ref->size_is;
9286771Sjb150015 
9296771Sjb150015 		myref.inner_flags = NDR_F_DIMENSION_IS;		/* convenient */
9306771Sjb150015 		myref.dimension_is = outer_ref->size_is;	/* convenient */
9316771Sjb150015 
9326771Sjb150015 		myref.pdu_offset = outer_ref->pdu_offset + 4;
9336771Sjb150015 
934*8334SJose.Borrego@Sun.COM 		rc = ndr_inner(&myref);
9356771Sjb150015 		if (!rc)
9366771Sjb150015 			return (rc);		/* error already set */
9376771Sjb150015 	}
9385772Sas200622 
939*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
9405772Sas200622 	return (1);
9415772Sas200622 }
9425772Sas200622 
9435772Sas200622 int
944*8334SJose.Borrego@Sun.COM ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
9455772Sas200622 {
946*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = outer_ref->stream;
947*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t	*ti = outer_ref->ti;
948*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
9495772Sas200622 	char 		*valp = NULL;
9505772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
9515772Sas200622 	int		is_union = NDR_IS_UNION(ti);
9525772Sas200622 	int		is_string = NDR_IS_STRING(ti);
9535772Sas200622 	unsigned long	size_is;
9545772Sas200622 	int		rc;
9555772Sas200622 	unsigned	n_hdr;
9565772Sas200622 	unsigned	n_fixed;
9575772Sas200622 	unsigned	n_variable;
9585772Sas200622 	unsigned	n_alloc;
9595772Sas200622 	unsigned	n_pdu_total;
9605772Sas200622 	int		params;
9615772Sas200622 
9625772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
9635772Sas200622 
9645772Sas200622 	assert(is_varlen && !is_string && !is_union);
9655772Sas200622 	assert(params == NDR_F_NONE);
9665772Sas200622 
9675772Sas200622 	/* conformant header for this */
9685772Sas200622 	n_hdr = 4;
9695772Sas200622 
9705772Sas200622 	/* fixed part -- exactly one of these */
9715772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
9725772Sas200622 
9735772Sas200622 	/* variable part -- exactly size_of of these */
9745772Sas200622 	n_variable = 0;		/* 0 for the moment */
9755772Sas200622 
9765772Sas200622 	/* sum them up to determine the PDU space required */
9775772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
9785772Sas200622 
9795772Sas200622 	/* similar sum to determine how much local memory is required */
9805772Sas200622 	n_alloc = n_fixed + n_variable;
9815772Sas200622 
9825772Sas200622 	/* For the moment, grow enough for the fixed-size part */
983*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
9845772Sas200622 	if (!rc)
9855772Sas200622 		return (rc);		/* error already set */
9865772Sas200622 
987*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
9885772Sas200622 	case NDR_M_OP_MARSHALL:
9895772Sas200622 		/*
9905772Sas200622 		 * We don't know the size yet. We have to wait for
9915772Sas200622 		 * it. Proceed with the fixed-size part, and await
992*8334SJose.Borrego@Sun.COM 		 * the call to ndr_size_is().
9935772Sas200622 		 */
9945772Sas200622 		size_is = 0;
995*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
9965772Sas200622 		if (!rc)
9975772Sas200622 			return (0);	/* error already set */
9985772Sas200622 
9995772Sas200622 		valp = outer_ref->datum;
10005772Sas200622 		assert(valp);
10015772Sas200622 		if (outer_ref->backptr) {
10025772Sas200622 			assert(valp == *outer_ref->backptr);
10035772Sas200622 		}
10045772Sas200622 		break;
10055772Sas200622 
10065772Sas200622 	case NDR_M_OP_UNMARSHALL:
10075772Sas200622 		/*
10085772Sas200622 		 * We know the size of the variable part because
10095772Sas200622 		 * of the CONFORMANT header. We will verify
10105772Sas200622 		 * the header against the [size_is(X)] advice
1011*8334SJose.Borrego@Sun.COM 		 * later when ndr_size_is() is called.
10125772Sas200622 		 */
1013*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
10145772Sas200622 		if (!rc)
10155772Sas200622 			return (0);	/* error already set */
10165772Sas200622 
10175772Sas200622 		/* recalculate metrics */
10185772Sas200622 		n_variable = size_is * ti->pdu_size_variable_part;
10195772Sas200622 		n_pdu_total = n_hdr + n_fixed + n_variable;
10205772Sas200622 		n_alloc = n_fixed + n_variable;
10215772Sas200622 
1022*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_grow(outer_ref, n_pdu_total);
10235772Sas200622 		if (!rc)
10245772Sas200622 			return (rc);		/* error already set */
10255772Sas200622 
10265772Sas200622 		outer_ref->size_is = size_is; /* verified later */
10275772Sas200622 
1028*8334SJose.Borrego@Sun.COM 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
10295772Sas200622 		if (!valp) {
10305772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
10315772Sas200622 			return (0);
10325772Sas200622 		}
10335772Sas200622 		if (outer_ref->backptr)
10345772Sas200622 			*outer_ref->backptr = valp;
10355772Sas200622 		outer_ref->datum = valp;
10365772Sas200622 		break;
10375772Sas200622 
10385772Sas200622 	default:
10395772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
10405772Sas200622 		return (0);
10415772Sas200622 	}
10425772Sas200622 
10436771Sjb150015 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
10446771Sjb150015 	outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
10456771Sjb150015 	outer_ref->inner_flags = NDR_F_NONE;   /* indicate pending */
10466771Sjb150015 
10475772Sas200622 	bzero(&myref, sizeof (myref));
1048*8334SJose.Borrego@Sun.COM 	myref.stream = nds;
10495772Sas200622 	myref.enclosing = outer_ref;
10505772Sas200622 	myref.ti = outer_ref->ti;
10515772Sas200622 	myref.datum = outer_ref->datum;
10525772Sas200622 	myref.name = "CONFORMANT-CONSTRUCT";
10535772Sas200622 	myref.outer_flags = NDR_F_NONE;
10545772Sas200622 	myref.inner_flags = NDR_F_NONE;
10555772Sas200622 	myref.size_is = outer_ref->size_is;
10565772Sas200622 
10575772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 4;
10585772Sas200622 
1059*8334SJose.Borrego@Sun.COM 	rc = ndr_inner(&myref);
10605772Sas200622 	if (!rc)
10615772Sas200622 		return (rc);		/* error already set */
10625772Sas200622 
1063*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
10645772Sas200622 
10655772Sas200622 	if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
10665772Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
10675772Sas200622 		return (0);
10685772Sas200622 	}
10695772Sas200622 
10705772Sas200622 	return (1);
10715772Sas200622 }
10725772Sas200622 
10735772Sas200622 int
1074*8334SJose.Borrego@Sun.COM ndr_size_is(ndr_ref_t *ref)
10755772Sas200622 {
1076*8334SJose.Borrego@Sun.COM 	ndr_stream_t 		*nds = ref->stream;
1077*8334SJose.Borrego@Sun.COM 	ndr_ref_t 		*outer_ref = nds->outer_current;
1078*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t		*ti = outer_ref->ti;
10795772Sas200622 	unsigned long		size_is;
10805772Sas200622 	int			rc;
10815772Sas200622 	unsigned		n_hdr;
10825772Sas200622 	unsigned		n_fixed;
10835772Sas200622 	unsigned		n_variable;
10845772Sas200622 	unsigned		n_pdu_total;
10855772Sas200622 
10865772Sas200622 	assert(ref->inner_flags & NDR_F_SIZE_IS);
10875772Sas200622 	size_is = ref->size_is;
10885772Sas200622 
10895772Sas200622 	if (outer_ref->type_flags != NDR_F_SIZE_IS) {
10905772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
10915772Sas200622 		return (0);
10925772Sas200622 	}
10935772Sas200622 
10945772Sas200622 	if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
10955772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
10965772Sas200622 		return (0);
10975772Sas200622 	}
10985772Sas200622 
1099*8334SJose.Borrego@Sun.COM 	/* repeat metrics, see ndr_conformant_construct() above */
11005772Sas200622 	n_hdr = 4;
11015772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
11025772Sas200622 	n_variable = size_is * ti->pdu_size_variable_part;
11035772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
11045772Sas200622 
1105*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
11065772Sas200622 	if (!rc)
11075772Sas200622 		return (rc);		/* error already set */
11085772Sas200622 
1109*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
11105772Sas200622 	case NDR_M_OP_MARSHALL:
11115772Sas200622 		/*
11125772Sas200622 		 * We have to set the sizing header and extend
11135772Sas200622 		 * the size of the PDU (already done).
11145772Sas200622 		 */
1115*8334SJose.Borrego@Sun.COM 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
11165772Sas200622 		if (!rc)
11175772Sas200622 			return (0);	/* error already set */
11185772Sas200622 		break;
11195772Sas200622 
11205772Sas200622 	case NDR_M_OP_UNMARSHALL:
11215772Sas200622 		/*
1122*8334SJose.Borrego@Sun.COM 		 * Allocation done during ndr_conformant_construct().
11235772Sas200622 		 * All we are doing here is verifying that the
11245772Sas200622 		 * intended size (ref->size_is) matches the sizing header.
11255772Sas200622 		 */
11265772Sas200622 		if (size_is != outer_ref->size_is) {
11275772Sas200622 			NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
11285772Sas200622 			return (0);
11295772Sas200622 		}
11305772Sas200622 		break;
11315772Sas200622 
11325772Sas200622 	default:
11335772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
11345772Sas200622 		return (0);
11355772Sas200622 	}
11365772Sas200622 
11375772Sas200622 	outer_ref->inner_flags |= NDR_F_SIZE_IS;
11385772Sas200622 	outer_ref->size_is = ref->size_is;
11395772Sas200622 	return (1);
11405772Sas200622 }
11415772Sas200622 
11425772Sas200622 int
1143*8334SJose.Borrego@Sun.COM ndr_outer_string(ndr_ref_t *outer_ref)
11445772Sas200622 {
1145*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = outer_ref->stream;
1146*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t 	*ti = outer_ref->ti;
1147*8334SJose.Borrego@Sun.COM 	ndr_ref_t	myref;
11485772Sas200622 	char 		*valp = NULL;
11495772Sas200622 	unsigned	is_varlen = ti->pdu_size_variable_part;
11505772Sas200622 	int		is_union = NDR_IS_UNION(ti);
11515772Sas200622 	int		is_string = NDR_IS_STRING(ti);
11525772Sas200622 	int		rc;
11535772Sas200622 	unsigned	n_zeroes;
11545772Sas200622 	unsigned	ix;
11555772Sas200622 	unsigned long	size_is;
11565772Sas200622 	unsigned long	first_is;
11575772Sas200622 	unsigned long	length_is;
11585772Sas200622 	unsigned	n_hdr;
11595772Sas200622 	unsigned	n_fixed;
11605772Sas200622 	unsigned	n_variable;
11615772Sas200622 	unsigned	n_alloc;
11625772Sas200622 	unsigned	n_pdu_total;
11635772Sas200622 	int		params;
11645772Sas200622 
11655772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
11665772Sas200622 
11675772Sas200622 	assert(is_varlen && is_string && !is_union);
11685772Sas200622 	assert(params == NDR_F_NONE);
11695772Sas200622 
11705772Sas200622 	/* string header for this: size_is first_is length_is */
11715772Sas200622 	n_hdr = 12;
11725772Sas200622 
11735772Sas200622 	/* fixed part -- exactly none of these */
11745772Sas200622 	n_fixed = 0;
11755772Sas200622 
1176*8334SJose.Borrego@Sun.COM 	if (!ndr_outer_grow(outer_ref, n_hdr))
11775772Sas200622 		return (0);		/* error already set */
11785772Sas200622 
1179*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
11805772Sas200622 	case NDR_M_OP_MARSHALL:
11815772Sas200622 		valp = outer_ref->datum;
11825772Sas200622 		assert(valp);
11835772Sas200622 
11845772Sas200622 		if (outer_ref->backptr)
11855772Sas200622 			assert(valp == *outer_ref->backptr);
11865772Sas200622 
11875772Sas200622 		if (ti == &ndt_s_wchar) {
11885772Sas200622 			/*
11895772Sas200622 			 * size_is is the number of characters in the string,
11905772Sas200622 			 * including the null. We assume valp is UTF-8 encoded.
11915772Sas200622 			 * We can use mts_wcequiv_strlen for ASCII, extended
11925772Sas200622 			 * ASCII or Unicode (UCS-2).
11935772Sas200622 			 */
11945772Sas200622 			size_is = (mts_wcequiv_strlen(valp) /
11955772Sas200622 			    sizeof (mts_wchar_t)) + 1;
11965772Sas200622 
11975772Sas200622 			if (size_is > NDR_STRING_MAX) {
11985772Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
11995772Sas200622 				return (0);
12005772Sas200622 			}
12015772Sas200622 		} else {
12025772Sas200622 			valp = outer_ref->datum;
12035772Sas200622 			n_zeroes = 0;
12045772Sas200622 			for (ix = 0; ix < 1024; ix++) {
12055772Sas200622 				if (valp[ix] == 0) {
12065772Sas200622 					n_zeroes++;
12075772Sas200622 					if (n_zeroes >= is_varlen &&
12085772Sas200622 					    ix % is_varlen == 0) {
12095772Sas200622 						break;
12105772Sas200622 					}
12115772Sas200622 				} else {
12125772Sas200622 					n_zeroes = 0;
12135772Sas200622 				}
12145772Sas200622 			}
12155772Sas200622 			if (ix >= 1024) {
12165772Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
12175772Sas200622 				return (0);
12185772Sas200622 			}
12195772Sas200622 			size_is = ix+1;
12205772Sas200622 		}
12215772Sas200622 
12225772Sas200622 		first_is = 0;
12235772Sas200622 
1224*8334SJose.Borrego@Sun.COM 		if (nds->flags & NDS_F_NOTERM)
12255772Sas200622 			length_is = size_is - 1;
12265772Sas200622 		else
12275772Sas200622 			length_is = size_is;
12285772Sas200622 
1229*8334SJose.Borrego@Sun.COM 		if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
1230*8334SJose.Borrego@Sun.COM 		    !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
1231*8334SJose.Borrego@Sun.COM 		    !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
12325772Sas200622 			return (0);		/* error already set */
12335772Sas200622 		break;
12345772Sas200622 
12355772Sas200622 	case NDR_M_OP_UNMARSHALL:
1236*8334SJose.Borrego@Sun.COM 		if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
1237*8334SJose.Borrego@Sun.COM 		    !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
1238*8334SJose.Borrego@Sun.COM 		    !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
12395772Sas200622 			return (0);		/* error already set */
12405772Sas200622 
12415772Sas200622 		/*
12425772Sas200622 		 * In addition to the first_is check, we used to check that
12435772Sas200622 		 * size_is or size_is-1 was equal to length_is but Windows95
12445772Sas200622 		 * doesn't conform to this "rule" (see variable part below).
12455772Sas200622 		 * The srvmgr tool for Windows95 sent the following values
12465772Sas200622 		 * for a path string:
12475772Sas200622 		 *
12485772Sas200622 		 *	size_is   = 261 (0x105)
12495772Sas200622 		 *	first_is  = 0
12505772Sas200622 		 *	length_is = 53  (0x35)
12515772Sas200622 		 *
12525772Sas200622 		 * The length_is was correct (for the given path) but the
12535772Sas200622 		 * size_is was the maximum path length rather than being
12545772Sas200622 		 * related to length_is.
12555772Sas200622 		 */
12565772Sas200622 		if (first_is != 0) {
12575772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
12585772Sas200622 			return (0);
12595772Sas200622 		}
12605772Sas200622 
12615772Sas200622 		if (ti == &ndt_s_wchar) {
12625772Sas200622 			/*
12635772Sas200622 			 * Decoding Unicode to UTF-8; we need to allow
12645772Sas200622 			 * for the maximum possible char size. It would
12655772Sas200622 			 * be nice to use mbequiv_strlen but the string
12665772Sas200622 			 * may not be null terminated.
12675772Sas200622 			 */
12685772Sas200622 			n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
12695772Sas200622 		} else {
12705772Sas200622 			n_alloc = (size_is + 1) * is_varlen;
12715772Sas200622 		}
12725772Sas200622 
1273*8334SJose.Borrego@Sun.COM 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
12745772Sas200622 		if (!valp) {
12755772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
12765772Sas200622 			return (0);
12775772Sas200622 		}
12785772Sas200622 
12795772Sas200622 		bzero(valp, (size_is+1) * is_varlen);
12805772Sas200622 
12815772Sas200622 		if (outer_ref->backptr)
12825772Sas200622 			*outer_ref->backptr = valp;
12835772Sas200622 		outer_ref->datum = valp;
12845772Sas200622 		break;
12855772Sas200622 
12865772Sas200622 	default:
12875772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
12885772Sas200622 		return (0);
12895772Sas200622 	}
12905772Sas200622 
12915772Sas200622 	/*
12925772Sas200622 	 * Variable part - exactly length_is of these.
12935772Sas200622 	 *
12945772Sas200622 	 * Usually, length_is is same as size_is and includes nul.
12955772Sas200622 	 * Some protocols use length_is = size_is-1, and length_is does
12965772Sas200622 	 * not include the nul (which is more consistent with DCE spec).
12975772Sas200622 	 * If the length_is is 0, there is no data following the
12985772Sas200622 	 * sizing header, regardless of size_is.
12995772Sas200622 	 */
13005772Sas200622 	n_variable = length_is * is_varlen;
13015772Sas200622 
13025772Sas200622 	/* sum them up to determine the PDU space required */
13035772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
13045772Sas200622 
13055772Sas200622 	/* similar sum to determine how much local memory is required */
13065772Sas200622 	n_alloc = n_fixed + n_variable;
13075772Sas200622 
1308*8334SJose.Borrego@Sun.COM 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
13095772Sas200622 	if (!rc)
13105772Sas200622 		return (rc);		/* error already set */
13115772Sas200622 
13125772Sas200622 	if (length_is > 0) {
13135772Sas200622 		bzero(&myref, sizeof (myref));
1314*8334SJose.Borrego@Sun.COM 		myref.stream = nds;
13155772Sas200622 		myref.enclosing = outer_ref;
13165772Sas200622 		myref.ti = outer_ref->ti;
13175772Sas200622 		myref.datum = outer_ref->datum;
13185772Sas200622 		myref.name = "OUTER-STRING";
13195772Sas200622 		myref.outer_flags = NDR_F_IS_STRING;
13205772Sas200622 		myref.inner_flags = NDR_F_NONE;
13215772Sas200622 
13225772Sas200622 		/*
1323*8334SJose.Borrego@Sun.COM 		 * Set up size_is and strlen_is for ndr_s_wchar.
13245772Sas200622 		 */
13255772Sas200622 		myref.size_is = size_is;
13265772Sas200622 		myref.strlen_is = length_is;
13275772Sas200622 	}
13285772Sas200622 
13295772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 12;
13305772Sas200622 
13315772Sas200622 	/*
13325772Sas200622 	 * Don't try to decode empty strings.
13335772Sas200622 	 */
13345772Sas200622 	if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
1335*8334SJose.Borrego@Sun.COM 		nds->pdu_scan_offset = outer_ref->pdu_end_offset;
13365772Sas200622 		return (1);
13375772Sas200622 	}
13385772Sas200622 
13395772Sas200622 	if ((size_is != 0) && (length_is != 0)) {
1340*8334SJose.Borrego@Sun.COM 		rc = ndr_inner(&myref);
13415772Sas200622 		if (!rc)
13425772Sas200622 			return (rc);		/* error already set */
13435772Sas200622 	}
13445772Sas200622 
1345*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
13465772Sas200622 	return (1);
13475772Sas200622 }
13485772Sas200622 
13495772Sas200622 int
1350*8334SJose.Borrego@Sun.COM ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
13515772Sas200622     unsigned long *sizing_p)
13525772Sas200622 {
1353*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = outer_ref->stream;
1354*8334SJose.Borrego@Sun.COM 	unsigned long	pdu_offset;
1355*8334SJose.Borrego@Sun.COM 	int		rc;
13565772Sas200622 
13575772Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
13585772Sas200622 
1359*8334SJose.Borrego@Sun.COM 	if (pdu_offset < nds->outer_current->pdu_offset ||
1360*8334SJose.Borrego@Sun.COM 	    pdu_offset > nds->outer_current->pdu_end_offset ||
1361*8334SJose.Borrego@Sun.COM 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
13625772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
13635772Sas200622 		return (0);
13645772Sas200622 	}
13655772Sas200622 
1366*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
13675772Sas200622 	case NDR_M_OP_MARSHALL:
13685772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
13695772Sas200622 		return (0);
13705772Sas200622 
13715772Sas200622 	case NDR_M_OP_UNMARSHALL:
1372*8334SJose.Borrego@Sun.COM 		rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1373*8334SJose.Borrego@Sun.COM 		    nds->swap, outer_ref);
13745772Sas200622 		break;
13755772Sas200622 
13765772Sas200622 	default:
13775772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
13785772Sas200622 		return (0);
13795772Sas200622 	}
13805772Sas200622 
13815772Sas200622 	return (rc);
13825772Sas200622 }
13835772Sas200622 
13845772Sas200622 int
1385*8334SJose.Borrego@Sun.COM ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
13865772Sas200622     unsigned long *sizing_p)
13875772Sas200622 {
1388*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = outer_ref->stream;
1389*8334SJose.Borrego@Sun.COM 	unsigned long	pdu_offset;
1390*8334SJose.Borrego@Sun.COM 	int		rc;
13915772Sas200622 
13925772Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
13935772Sas200622 
1394*8334SJose.Borrego@Sun.COM 	if (pdu_offset < nds->outer_current->pdu_offset ||
1395*8334SJose.Borrego@Sun.COM 	    pdu_offset > nds->outer_current->pdu_end_offset ||
1396*8334SJose.Borrego@Sun.COM 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
13975772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
13985772Sas200622 		return (0);
13995772Sas200622 	}
14005772Sas200622 
1401*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
14025772Sas200622 	case NDR_M_OP_MARSHALL:
1403*8334SJose.Borrego@Sun.COM 		rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1404*8334SJose.Borrego@Sun.COM 		    nds->swap, outer_ref);
14055772Sas200622 		break;
14065772Sas200622 
14075772Sas200622 	case NDR_M_OP_UNMARSHALL:
14085772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
14095772Sas200622 		return (0);
14105772Sas200622 
14115772Sas200622 	default:
14125772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14135772Sas200622 		return (0);
14145772Sas200622 	}
14155772Sas200622 
14165772Sas200622 	return (rc);
14175772Sas200622 }
14185772Sas200622 
14195772Sas200622 /*
14205772Sas200622  * All OUTER constructs begin on a mod4 (dword) boundary - except
14215772Sas200622  * for the ones that don't: some MSRPC calls appear to use word or
14225772Sas200622  * packed alignment.  Strings appear to be dword aligned.
14235772Sas200622  */
14245772Sas200622 int
1425*8334SJose.Borrego@Sun.COM ndr_outer_align(ndr_ref_t *outer_ref)
14265772Sas200622 {
1427*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = outer_ref->stream;
1428*8334SJose.Borrego@Sun.COM 	int		rc;
1429*8334SJose.Borrego@Sun.COM 	unsigned	n_pad;
1430*8334SJose.Borrego@Sun.COM 	unsigned	align;
14315772Sas200622 
14325772Sas200622 	if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
14335772Sas200622 		align = outer_ref->ti->alignment;
1434*8334SJose.Borrego@Sun.COM 		n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
14355772Sas200622 	} else {
1436*8334SJose.Borrego@Sun.COM 		n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
14375772Sas200622 	}
14385772Sas200622 
14395772Sas200622 	if (n_pad == 0)
14405772Sas200622 		return (1);	/* already aligned, often the case */
14415772Sas200622 
1442*8334SJose.Borrego@Sun.COM 	if (!ndr_outer_grow(outer_ref, n_pad))
14435772Sas200622 		return (0);	/* error already set */
14445772Sas200622 
1445*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
14465772Sas200622 	case NDR_M_OP_MARSHALL:
1447*8334SJose.Borrego@Sun.COM 		rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
14485772Sas200622 		if (!rc) {
14495772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
14505772Sas200622 			return (0);
14515772Sas200622 		}
14525772Sas200622 		break;
14535772Sas200622 
14545772Sas200622 	case NDR_M_OP_UNMARSHALL:
14555772Sas200622 		break;
14565772Sas200622 
14575772Sas200622 	default:
14585772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14595772Sas200622 		return (0);
14605772Sas200622 	}
14615772Sas200622 
1462*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset += n_pad;
14635772Sas200622 	return (1);
14645772Sas200622 }
14655772Sas200622 
14665772Sas200622 int
1467*8334SJose.Borrego@Sun.COM ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
14685772Sas200622 {
1469*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = outer_ref->stream;
1470*8334SJose.Borrego@Sun.COM 	unsigned long	pdu_want_size;
1471*8334SJose.Borrego@Sun.COM 	int		rc, is_ok = 0;
14725772Sas200622 
1473*8334SJose.Borrego@Sun.COM 	pdu_want_size = nds->pdu_scan_offset + n_total;
14745772Sas200622 
1475*8334SJose.Borrego@Sun.COM 	if (pdu_want_size <= nds->pdu_max_size) {
14765772Sas200622 		is_ok = 1;
14775772Sas200622 	}
14785772Sas200622 
1479*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
14805772Sas200622 	case NDR_M_OP_MARSHALL:
14815772Sas200622 		if (is_ok)
14825772Sas200622 			break;
1483*8334SJose.Borrego@Sun.COM 		rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
14845772Sas200622 		if (!rc) {
14855772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
14865772Sas200622 			return (0);
14875772Sas200622 		}
14885772Sas200622 		break;
14895772Sas200622 
14905772Sas200622 	case NDR_M_OP_UNMARSHALL:
14915772Sas200622 		if (is_ok)
14925772Sas200622 			break;
14935772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
14945772Sas200622 		return (0);
14955772Sas200622 
14965772Sas200622 	default:
14975772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14985772Sas200622 		return (0);
14995772Sas200622 	}
15005772Sas200622 
1501*8334SJose.Borrego@Sun.COM 	if (nds->pdu_size < pdu_want_size)
1502*8334SJose.Borrego@Sun.COM 		nds->pdu_size = pdu_want_size;
15035772Sas200622 
15045772Sas200622 	outer_ref->pdu_end_offset = pdu_want_size;
15055772Sas200622 	return (1);
15065772Sas200622 }
15075772Sas200622 
15085772Sas200622 /*
15095772Sas200622  * INNER ELEMENTS
15105772Sas200622  *
15115772Sas200622  * The local datum (arg_ref->datum) already exists, there is no need to
15125772Sas200622  * malloc() it.  The datum should point at a member of a structure.
15135772Sas200622  *
1514*8334SJose.Borrego@Sun.COM  * For the most part, ndr_inner() and its helpers are just a sanity
15155772Sas200622  * check.  The underlying ti->ndr_func() could be called immediately
15165772Sas200622  * for non-pointer elements.  For the sake of robustness, we detect
15175772Sas200622  * run-time errors here.  Most of the situations this protects against
15185772Sas200622  * have already been checked by the IDL compiler.  This is also a
15195772Sas200622  * common point for processing of all data, and so is a convenient
15205772Sas200622  * place to work from for debugging.
15215772Sas200622  */
15225772Sas200622 int
1523*8334SJose.Borrego@Sun.COM ndr_inner(ndr_ref_t *arg_ref)
15245772Sas200622 {
1525*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t 	*ti = arg_ref->ti;
15265772Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
15275772Sas200622 	int	is_union = NDR_IS_UNION(ti);
15285772Sas200622 	int	error = NDR_ERR_INNER_PARAMS_BAD;
15295772Sas200622 	int	params;
15305772Sas200622 
15315772Sas200622 	params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
15325772Sas200622 
15335772Sas200622 	switch (params) {
15345772Sas200622 	case NDR_F_NONE:
15355772Sas200622 		if (is_union) {
15365772Sas200622 			error = NDR_ERR_SWITCH_VALUE_MISSING;
15375772Sas200622 			break;
15385772Sas200622 		}
15395772Sas200622 		return (*ti->ndr_func)(arg_ref);
15405772Sas200622 		break;
15415772Sas200622 
15425772Sas200622 	case NDR_F_SIZE_IS:
15435772Sas200622 	case NDR_F_DIMENSION_IS:
15445772Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:   /* pointer to something */
15455772Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
15465772Sas200622 		if (is_varlen) {
15475772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
15485772Sas200622 			break;
15495772Sas200622 		}
15505772Sas200622 		if (is_union) {
15515772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15525772Sas200622 			break;
15535772Sas200622 		}
15545772Sas200622 		if (params & NDR_F_IS_POINTER)
1555*8334SJose.Borrego@Sun.COM 			return (ndr_inner_pointer(arg_ref));
15565772Sas200622 		else if (params & NDR_F_IS_REFERENCE)
1557*8334SJose.Borrego@Sun.COM 			return (ndr_inner_reference(arg_ref));
15585772Sas200622 		else
1559*8334SJose.Borrego@Sun.COM 			return (ndr_inner_array(arg_ref));
15605772Sas200622 		break;
15615772Sas200622 
15625772Sas200622 	case NDR_F_IS_POINTER:	/* type is pointer to one something */
15635772Sas200622 		if (is_union) {
15645772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15655772Sas200622 			break;
15665772Sas200622 		}
1567*8334SJose.Borrego@Sun.COM 		return (ndr_inner_pointer(arg_ref));
15685772Sas200622 		break;
15695772Sas200622 
15705772Sas200622 	case NDR_F_IS_REFERENCE:	/* type is pointer to one something */
15715772Sas200622 		if (is_union) {
15725772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15735772Sas200622 			break;
15745772Sas200622 		}
1575*8334SJose.Borrego@Sun.COM 		return (ndr_inner_reference(arg_ref));
15765772Sas200622 		break;
15775772Sas200622 
15785772Sas200622 	case NDR_F_SWITCH_IS:
15795772Sas200622 		if (!is_union) {
15805772Sas200622 			error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
15815772Sas200622 			break;
15825772Sas200622 		}
15835772Sas200622 		return (*ti->ndr_func)(arg_ref);
15845772Sas200622 		break;
15855772Sas200622 
15865772Sas200622 	default:
15875772Sas200622 		error = NDR_ERR_INNER_PARAMS_BAD;
15885772Sas200622 		break;
15895772Sas200622 	}
15905772Sas200622 
15915772Sas200622 	/*
15925772Sas200622 	 * If we get here, something is wrong. Most likely,
15935772Sas200622 	 * the params flags do not match
15945772Sas200622 	 */
15955772Sas200622 	NDR_SET_ERROR(arg_ref, error);
15965772Sas200622 	return (0);
15975772Sas200622 }
15985772Sas200622 
15995772Sas200622 int
1600*8334SJose.Borrego@Sun.COM ndr_inner_pointer(ndr_ref_t *arg_ref)
16015772Sas200622 {
1602*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = arg_ref->stream;
16035772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1604*8334SJose.Borrego@Sun.COM 	char 		**valpp = (char **)arg_ref->datum;
1605*8334SJose.Borrego@Sun.COM 	ndr_ref_t 	*outer_ref;
16065772Sas200622 
1607*8334SJose.Borrego@Sun.COM 	if (!ndr__ulong(arg_ref))
16085772Sas200622 		return (0);	/* error */
16095772Sas200622 	if (!*valpp)
16105772Sas200622 		return (1);	/* NULL pointer */
16115772Sas200622 
1612*8334SJose.Borrego@Sun.COM 	outer_ref = ndr_enter_outer_queue(arg_ref);
16135772Sas200622 	if (!outer_ref)
16145772Sas200622 		return (0);	/* error already set */
16155772Sas200622 
16165772Sas200622 	/* move advice in inner_flags to outer_flags sans pointer */
16175772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
16185772Sas200622 	outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
16195772Sas200622 #ifdef NDR_INNER_NOT_YET
16205772Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
16215772Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
16225772Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
16235772Sas200622 	}
16245772Sas200622 #endif /* NDR_INNER_NOT_YET */
16255772Sas200622 
16265772Sas200622 	outer_ref->backptr = valpp;
16275772Sas200622 
1628*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
16295772Sas200622 	case NDR_M_OP_MARSHALL:
16305772Sas200622 		outer_ref->datum = *valpp;
16315772Sas200622 		break;
16325772Sas200622 
16335772Sas200622 	case NDR_M_OP_UNMARSHALL:
16345772Sas200622 		/*
16355772Sas200622 		 * This is probably wrong if the application allocated
16365772Sas200622 		 * memory in advance.  Indicate no value for now.
16375772Sas200622 		 * ONC RPC handles this case.
16385772Sas200622 		 */
16395772Sas200622 		*valpp = 0;
16405772Sas200622 		outer_ref->datum = 0;
16415772Sas200622 		break;
16425772Sas200622 	}
16435772Sas200622 
16445772Sas200622 	return (1);		/* pointer dereference scheduled */
16455772Sas200622 }
16465772Sas200622 
16475772Sas200622 int
1648*8334SJose.Borrego@Sun.COM ndr_inner_reference(ndr_ref_t *arg_ref)
16495772Sas200622 {
1650*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*nds = arg_ref->stream;
16515772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1652*8334SJose.Borrego@Sun.COM 	char		**valpp = (char **)arg_ref->datum;
1653*8334SJose.Borrego@Sun.COM 	ndr_ref_t	*outer_ref;
16545772Sas200622 
1655*8334SJose.Borrego@Sun.COM 	outer_ref = ndr_enter_outer_queue(arg_ref);
16565772Sas200622 	if (!outer_ref)
16575772Sas200622 		return (0);	/* error already set */
16585772Sas200622 
16595772Sas200622 	/* move advice in inner_flags to outer_flags sans pointer */
16605772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
16615772Sas200622 	outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
16625772Sas200622 #ifdef NDR_INNER_REF_NOT_YET
16635772Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
16645772Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
16655772Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
16665772Sas200622 	}
16675772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */
16685772Sas200622 
16695772Sas200622 	outer_ref->backptr = valpp;
16705772Sas200622 
1671*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
16725772Sas200622 	case NDR_M_OP_MARSHALL:
16735772Sas200622 		outer_ref->datum = *valpp;
16745772Sas200622 		break;
16755772Sas200622 
16765772Sas200622 	case NDR_M_OP_UNMARSHALL:
16775772Sas200622 		/*
16785772Sas200622 		 * This is probably wrong if the application allocated
16795772Sas200622 		 * memory in advance.  Indicate no value for now.
16805772Sas200622 		 * ONC RPC handles this case.
16815772Sas200622 		 */
16825772Sas200622 		*valpp = 0;
16835772Sas200622 		outer_ref->datum = 0;
16845772Sas200622 		break;
16855772Sas200622 	}
16865772Sas200622 
16875772Sas200622 	return (1);		/* pointer dereference scheduled */
16885772Sas200622 }
16895772Sas200622 
16905772Sas200622 int
1691*8334SJose.Borrego@Sun.COM ndr_inner_array(ndr_ref_t *encl_ref)
16925772Sas200622 {
1693*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t		*ti = encl_ref->ti;
1694*8334SJose.Borrego@Sun.COM 	ndr_ref_t		myref;
16955772Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
16965772Sas200622 	unsigned long		n_elem;
16975772Sas200622 	unsigned long		i;
16985772Sas200622 	char			name[30];
16995772Sas200622 
17005772Sas200622 	if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
17015772Sas200622 		/* now is the time to check/set size */
1702*8334SJose.Borrego@Sun.COM 		if (!ndr_size_is(encl_ref))
17035772Sas200622 			return (0);	/* error already set */
17045772Sas200622 		n_elem = encl_ref->size_is;
17055772Sas200622 	} else {
17065772Sas200622 		assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
17075772Sas200622 		n_elem = encl_ref->dimension_is;
17085772Sas200622 	}
17095772Sas200622 
17105772Sas200622 	bzero(&myref, sizeof (myref));
17115772Sas200622 	myref.enclosing = encl_ref;
17125772Sas200622 	myref.stream = encl_ref->stream;
17135772Sas200622 	myref.packed_alignment = 0;
17145772Sas200622 	myref.ti = ti;
17155772Sas200622 	myref.inner_flags = NDR_F_NONE;
17165772Sas200622 
17175772Sas200622 	for (i = 0; i < n_elem; i++) {
17185772Sas200622 		(void) sprintf(name, "[%lu]", i);
17195772Sas200622 		myref.name = name;
17205772Sas200622 		myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
17215772Sas200622 		myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
17225772Sas200622 
1723*8334SJose.Borrego@Sun.COM 		if (!ndr_inner(&myref))
17245772Sas200622 			return (0);
17255772Sas200622 	}
17265772Sas200622 
17275772Sas200622 	return (1);
17285772Sas200622 }
17295772Sas200622 
17305772Sas200622 
17315772Sas200622 /*
17325772Sas200622  * BASIC TYPES
17335772Sas200622  */
17345772Sas200622 #define	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1735*8334SJose.Borrego@Sun.COM     extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
1736*8334SJose.Borrego@Sun.COM     ndr_typeinfo_t ndt_##TYPE = { \
17375772Sas200622 	1,		/* NDR version */ \
17385772Sas200622 	(SIZE)-1,	/* alignment */ \
17395772Sas200622 	NDR_F_NONE,	/* flags */ \
1740*8334SJose.Borrego@Sun.COM 	ndr_##TYPE,	/* ndr_func */ \
17415772Sas200622 	SIZE,		/* pdu_size_fixed_part */ \
17425772Sas200622 	0,		/* pdu_size_variable_part */ \
17435772Sas200622 	SIZE,		/* c_size_fixed_part */ \
17445772Sas200622 	0,		/* c_size_variable_part */ \
17455772Sas200622 	}; \
1746*8334SJose.Borrego@Sun.COM     int ndr_##TYPE(struct ndr_reference *ref) { \
1747*8334SJose.Borrego@Sun.COM 	return (ndr_basic_integer(ref, SIZE)); \
17485772Sas200622 }
17495772Sas200622 
17505772Sas200622 #define	MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
1751*8334SJose.Borrego@Sun.COM     extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
1752*8334SJose.Borrego@Sun.COM     ndr_typeinfo_t ndt_s##TYPE = { \
17535772Sas200622 	1,		/* NDR version */ \
17545772Sas200622 	(SIZE)-1,	/* alignment */ \
17555772Sas200622 	NDR_F_STRING,	/* flags */ \
1756*8334SJose.Borrego@Sun.COM 	ndr_s##TYPE,	/* ndr_func */ \
17575772Sas200622 	0,		/* pdu_size_fixed_part */ \
17585772Sas200622 	SIZE,		/* pdu_size_variable_part */ \
17595772Sas200622 	0,		/* c_size_fixed_part */ \
17605772Sas200622 	SIZE,		/* c_size_variable_part */ \
17615772Sas200622 	}; \
1762*8334SJose.Borrego@Sun.COM     int ndr_s##TYPE(struct ndr_reference *ref) { \
1763*8334SJose.Borrego@Sun.COM 	return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
17645772Sas200622 }
17655772Sas200622 
17665772Sas200622 #define	MAKE_BASIC_TYPE(TYPE, SIZE) \
17675772Sas200622 	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
17685772Sas200622 	MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
17695772Sas200622 
1770*8334SJose.Borrego@Sun.COM int ndr_basic_integer(ndr_ref_t *, unsigned);
1771*8334SJose.Borrego@Sun.COM int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
17725772Sas200622 
17735772Sas200622 
17745772Sas200622 MAKE_BASIC_TYPE(_char, 1)
17755772Sas200622 MAKE_BASIC_TYPE(_uchar, 1)
17765772Sas200622 MAKE_BASIC_TYPE(_short, 2)
17775772Sas200622 MAKE_BASIC_TYPE(_ushort, 2)
17785772Sas200622 MAKE_BASIC_TYPE(_long, 4)
17795772Sas200622 MAKE_BASIC_TYPE(_ulong, 4)
17805772Sas200622 
17815772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2)
17825772Sas200622 
17835772Sas200622 int
1784*8334SJose.Borrego@Sun.COM ndr_basic_integer(ndr_ref_t *ref, unsigned size)
17855772Sas200622 {
1786*8334SJose.Borrego@Sun.COM 	ndr_stream_t 	*nds = ref->stream;
1787*8334SJose.Borrego@Sun.COM 	char 		*valp = (char *)ref->datum;
1788*8334SJose.Borrego@Sun.COM 	int		rc;
17895772Sas200622 
1790*8334SJose.Borrego@Sun.COM 	switch (nds->m_op) {
17915772Sas200622 	case NDR_M_OP_MARSHALL:
1792*8334SJose.Borrego@Sun.COM 		rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
1793*8334SJose.Borrego@Sun.COM 		    valp, nds->swap, ref);
17945772Sas200622 		break;
17955772Sas200622 
17965772Sas200622 	case NDR_M_OP_UNMARSHALL:
1797*8334SJose.Borrego@Sun.COM 		rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
1798*8334SJose.Borrego@Sun.COM 		    valp, nds->swap, ref);
17995772Sas200622 		break;
18005772Sas200622 
18015772Sas200622 	default:
18025772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
18035772Sas200622 		return (0);
18045772Sas200622 	}
18055772Sas200622 
18065772Sas200622 	return (rc);
18075772Sas200622 }
18085772Sas200622 
18095772Sas200622 int
1810*8334SJose.Borrego@Sun.COM ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
18115772Sas200622 {
18125772Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
18135772Sas200622 	unsigned		size = type_under->pdu_size_fixed_part;
18145772Sas200622 	char			*valp;
1815*8334SJose.Borrego@Sun.COM 	ndr_ref_t		myref;
18165772Sas200622 	unsigned long		i;
18175772Sas200622 	long			sense = 0;
18185772Sas200622 	char			name[30];
18195772Sas200622 
18205772Sas200622 	assert(size != 0);
18215772Sas200622 
18225772Sas200622 	bzero(&myref, sizeof (myref));
18235772Sas200622 	myref.enclosing = encl_ref;
18245772Sas200622 	myref.stream = encl_ref->stream;
18255772Sas200622 	myref.packed_alignment = 0;
18265772Sas200622 	myref.ti = type_under;
18275772Sas200622 	myref.inner_flags = NDR_F_NONE;
18285772Sas200622 	myref.name = name;
18295772Sas200622 
18305772Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
18315772Sas200622 		(void) sprintf(name, "[%lu]", i);
18325772Sas200622 		myref.pdu_offset = pdu_offset + i * size;
18335772Sas200622 		valp = encl_ref->datum + i * size;
18345772Sas200622 		myref.datum = valp;
18355772Sas200622 
1836*8334SJose.Borrego@Sun.COM 		if (!ndr_inner(&myref))
18375772Sas200622 			return (0);
18385772Sas200622 
18395772Sas200622 		switch (size) {
18405772Sas200622 		case 1:		sense = *valp; break;
18415772Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
18425772Sas200622 		case 2:		sense = *(short *)valp; break;
18435772Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
18445772Sas200622 		case 4:		sense = *(long *)valp; break;
18455772Sas200622 		}
18465772Sas200622 
18475772Sas200622 		if (!sense)
18485772Sas200622 			break;
18495772Sas200622 	}
18505772Sas200622 
18515772Sas200622 	return (1);
18525772Sas200622 }
18535772Sas200622 
18545772Sas200622 
1855*8334SJose.Borrego@Sun.COM extern int ndr_s_wchar(ndr_ref_t *encl_ref);
1856*8334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_s_wchar = {
18575772Sas200622 	1,		/* NDR version */
18585772Sas200622 	2-1,		/* alignment */
18595772Sas200622 	NDR_F_STRING,	/* flags */
1860*8334SJose.Borrego@Sun.COM 	ndr_s_wchar,	/* ndr_func */
18615772Sas200622 	0,		/* pdu_size_fixed_part */
18625772Sas200622 	2,		/* pdu_size_variable_part */
18635772Sas200622 	0,		/* c_size_fixed_part */
18645772Sas200622 	1,		/* c_size_variable_part */
18655772Sas200622 };
18665772Sas200622 
18675772Sas200622 
18685772Sas200622 /*
18695772Sas200622  * Hand coded wchar function because all strings are transported
18705772Sas200622  * as wide characters. During NDR_M_OP_MARSHALL, we convert from
18715772Sas200622  * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
18725772Sas200622  * convert from wide characters to multi-byte.
18735772Sas200622  *
18745772Sas200622  * It appeared that NT would sometimes leave a spurious character
18755772Sas200622  * in the data stream before the null wide_char, which would get
18765772Sas200622  * included in the string decode because we processed until the
18775772Sas200622  * null character. It now looks like NT does not always terminate
18785772Sas200622  * RPC Unicode strings and the terminating null is a side effect
18795772Sas200622  * of field alignment. So now we rely on the strlen_is (set up in
1880*8334SJose.Borrego@Sun.COM  * ndr_outer_string) of the enclosing reference. This may or may
18815772Sas200622  * not include the null but it doesn't matter, the algorithm will
18825772Sas200622  * get it right.
18835772Sas200622  */
18845772Sas200622 int
1885*8334SJose.Borrego@Sun.COM ndr_s_wchar(ndr_ref_t *encl_ref)
18865772Sas200622 {
1887*8334SJose.Borrego@Sun.COM 	ndr_stream_t		*nds = encl_ref->stream;
18885772Sas200622 	unsigned short		wide_char;
18895772Sas200622 	char 			*valp;
1890*8334SJose.Borrego@Sun.COM 	ndr_ref_t		myref;
18915772Sas200622 	unsigned long		i;
18925772Sas200622 	char			name[30];
18935772Sas200622 	int			count;
18945772Sas200622 	int			char_count = 0;
18955772Sas200622 
1896*8334SJose.Borrego@Sun.COM 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
18975772Sas200622 		/*
18985772Sas200622 		 * To avoid problems with zero length strings
18995772Sas200622 		 * we can just null terminate here and be done.
19005772Sas200622 		 */
19015772Sas200622 		if (encl_ref->strlen_is == 0) {
19025772Sas200622 			encl_ref->datum[0] = '\0';
19035772Sas200622 			return (1);
19045772Sas200622 		}
19055772Sas200622 	}
19065772Sas200622 
19075772Sas200622 	bzero(&myref, sizeof (myref));
19085772Sas200622 	myref.enclosing = encl_ref;
19095772Sas200622 	myref.stream = encl_ref->stream;
19105772Sas200622 	myref.packed_alignment = 0;
19115772Sas200622 	myref.ti = &ndt__wchar;
19125772Sas200622 	myref.inner_flags = NDR_F_NONE;
19135772Sas200622 	myref.datum = (char *)&wide_char;
19145772Sas200622 	myref.name = name;
19155772Sas200622 	myref.pdu_offset = encl_ref->pdu_offset;
19165772Sas200622 
19175772Sas200622 	valp = encl_ref->datum;
19185772Sas200622 	count = 0;
19195772Sas200622 
19205772Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
19215772Sas200622 		(void) sprintf(name, "[%lu]", i);
19225772Sas200622 
1923*8334SJose.Borrego@Sun.COM 		if (nds->m_op == NDR_M_OP_MARSHALL) {
19245772Sas200622 			count = mts_mbtowc((mts_wchar_t *)&wide_char, valp,
19255772Sas200622 			    MTS_MB_CHAR_MAX);
19265772Sas200622 			if (count < 0) {
19275772Sas200622 				return (0);
19285772Sas200622 			} else if (count == 0) {
19295772Sas200622 				if (encl_ref->strlen_is != encl_ref->size_is)
19305772Sas200622 					break;
19315772Sas200622 
19325772Sas200622 				/*
19335772Sas200622 				 * If the input char is 0, mbtowc
19345772Sas200622 				 * returns 0 without setting wide_char.
19355772Sas200622 				 * Set wide_char to 0 and a count of 1.
19365772Sas200622 				 */
19375772Sas200622 				wide_char = *valp;
19385772Sas200622 				count = 1;
19395772Sas200622 			}
19405772Sas200622 		}
19415772Sas200622 
1942*8334SJose.Borrego@Sun.COM 		if (!ndr_inner(&myref))
19435772Sas200622 			return (0);
19445772Sas200622 
1945*8334SJose.Borrego@Sun.COM 		if (nds->m_op == NDR_M_OP_UNMARSHALL) {
19465772Sas200622 			count = mts_wctomb(valp, wide_char);
19475772Sas200622 
19485772Sas200622 			if ((++char_count) == encl_ref->strlen_is) {
19495772Sas200622 				valp += count;
19505772Sas200622 				*valp = '\0';
19515772Sas200622 				break;
19525772Sas200622 			}
19535772Sas200622 		}
19545772Sas200622 
19555772Sas200622 		if (!wide_char)
19565772Sas200622 			break;
19575772Sas200622 
19585772Sas200622 		myref.pdu_offset += sizeof (wide_char);
19595772Sas200622 		valp += count;
19605772Sas200622 	}
19615772Sas200622 
19625772Sas200622 	return (1);
19635772Sas200622 }
19645772Sas200622 
19655772Sas200622 /*
19665772Sas200622  * Converts a multibyte character string to a little-endian, wide-char
19675772Sas200622  * string.  No more than nwchars wide characters are stored.
19685772Sas200622  * A terminating null wide character is appended if there is room.
19695772Sas200622  *
19705772Sas200622  * Returns the number of wide characters converted, not counting
19715772Sas200622  * any terminating null wide character.  Returns -1 if an invalid
19725772Sas200622  * multibyte character is encountered.
19735772Sas200622  */
19745772Sas200622 size_t
1975*8334SJose.Borrego@Sun.COM ndr_mbstowcs(ndr_stream_t *nds, mts_wchar_t *wcs, const char *mbs,
19765772Sas200622     size_t nwchars)
19775772Sas200622 {
19785772Sas200622 	mts_wchar_t *start = wcs;
19795772Sas200622 	int nbytes;
19805772Sas200622 
19815772Sas200622 	while (nwchars--) {
1982*8334SJose.Borrego@Sun.COM 		nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX);
19835772Sas200622 		if (nbytes < 0) {
19845772Sas200622 			*wcs = 0;
19855772Sas200622 			return ((size_t)-1);
19865772Sas200622 		}
19875772Sas200622 
19885772Sas200622 		if (*mbs == 0)
19895772Sas200622 			break;
19905772Sas200622 
19915772Sas200622 		++wcs;
19925772Sas200622 		mbs += nbytes;
19935772Sas200622 	}
19945772Sas200622 
19955772Sas200622 	return (wcs - start);
19965772Sas200622 }
19975772Sas200622 
19985772Sas200622 /*
19995772Sas200622  * Converts a multibyte character to a little-endian, wide-char, which
20005772Sas200622  * is stored in wcharp.  Up to nbytes bytes are examined.
20015772Sas200622  *
20025772Sas200622  * If mbchar is valid, returns the number of bytes processed in mbchar.
20035772Sas200622  * If mbchar is invalid, returns -1.  See also mts_mbtowc().
20045772Sas200622  */
20055772Sas200622 /*ARGSUSED*/
20065772Sas200622 int
2007*8334SJose.Borrego@Sun.COM ndr_mbtowc(ndr_stream_t *nds, mts_wchar_t *wcharp, const char *mbchar,
2008*8334SJose.Borrego@Sun.COM     size_t nbytes)
20095772Sas200622 {
20105772Sas200622 	int rc;
20115772Sas200622 
20125772Sas200622 	if ((rc = mts_mbtowc(wcharp, mbchar, nbytes)) < 0)
20135772Sas200622 		return (rc);
20145772Sas200622 
20155772Sas200622 #ifdef _BIG_ENDIAN
2016*8334SJose.Borrego@Sun.COM 	if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND))
20175772Sas200622 		*wcharp = BSWAP_16(*wcharp);
20185772Sas200622 #endif
20195772Sas200622 
20205772Sas200622 	return (rc);
20215772Sas200622 }
2022