xref: /illumos-gate/usr/src/lib/libmlrpc/common/ndr_process.c (revision 1ca4e8df0656724dae6eea0884d84d8d4c1aabb2)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24*1ca4e8dfSGordon Ross  *
2533f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
26*1ca4e8dfSGordon Ross  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
27da6c28aaSamw  */
28da6c28aaSamw 
29da6c28aaSamw /*
30da6c28aaSamw  * Network Data Representation (NDR) is a compatible subset of the DCE RPC
31da6c28aaSamw  * and MSRPC NDR.  NDR is used to move parameters consisting of
32da6c28aaSamw  * complicated trees of data constructs between an RPC client and server.
33da6c28aaSamw  */
34da6c28aaSamw 
3555bf511dSas #include <sys/byteorder.h>
36da6c28aaSamw #include <strings.h>
37da6c28aaSamw #include <assert.h>
38da6c28aaSamw #include <string.h>
393299f39fSGordon Ross #include <stdio.h>
40da6c28aaSamw #include <stdlib.h>
41da6c28aaSamw 
423299f39fSGordon Ross #include <libmlrpc.h>
433299f39fSGordon Ross #include <ndr_wchar.h>
44da6c28aaSamw 
45da6c28aaSamw #define	NDR_IS_UNION(T)	\
46da6c28aaSamw 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
47da6c28aaSamw #define	NDR_IS_STRING(T)	\
48da6c28aaSamw 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
49da6c28aaSamw 
508d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar;
51da6c28aaSamw 
52da6c28aaSamw /*
53da6c28aaSamw  * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
54da6c28aaSamw  *
55da6c28aaSamw  * Each parameter (call arguments and return values) is a TOP-MOST item.
56da6c28aaSamw  * A TOP-MOST item consists of one or more OUTER items.  An OUTER item
57da6c28aaSamw  * consists of one or more INNER items.  There are important differences
58da6c28aaSamw  * between each kind, which, primarily, have to do with the allocation
59da6c28aaSamw  * of memory to contain data structures and the order of processing.
60da6c28aaSamw  *
61da6c28aaSamw  * This is most easily demonstrated with a short example.
62da6c28aaSamw  * Consider these structures:
63da6c28aaSamw  *
64da6c28aaSamw  *	struct top_param {
65da6c28aaSamw  *		long		level;
66da6c28aaSamw  *		struct list *	head;
67da6c28aaSamw  *		long		count;
68da6c28aaSamw  *	};
69da6c28aaSamw  *
70da6c28aaSamw  *	struct list {
71da6c28aaSamw  *		struct list *	next;
72da6c28aaSamw  *		char *		str; // a string
73da6c28aaSamw  *	};
74da6c28aaSamw  *
75da6c28aaSamw  * Now, consider an instance tree like this:
76da6c28aaSamw  *
77da6c28aaSamw  *	+---------+       +-------+       +-------+
78da6c28aaSamw  *	|top_param|  +--->|list #1|  +--->|list #2|
79da6c28aaSamw  *	+---------+  |    +-------+  |    +-------+
80da6c28aaSamw  *	| level   |  |    | next ----+    | next --->(NULL)
81da6c28aaSamw  *	| head   ----+    | str  -->"foo" | str  -->"bar"
82da6c28aaSamw  *	| count   |       | flag  |       | flag  |
83da6c28aaSamw  *	+---------+       +-------+       +-------+
84da6c28aaSamw  *
85da6c28aaSamw  * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
86da6c28aaSamw  * The vertical bars (|) indicate OUTER construct boundaries.
87da6c28aaSamw  *
88da6c28aaSamw  *   +-----+----------------------+----------------------+-----+-----+-----+
89da6c28aaSamw  *   |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
90da6c28aaSamw  *   +-----+----------------------+----------------------+-----+-----+-----+
91da6c28aaSamw  *   level |<----------------------- head -------------------------->|count
92da6c28aaSamw  *   TOP    TOP                                                       TOP
93da6c28aaSamw  *
94da6c28aaSamw  * Here's what to notice:
95da6c28aaSamw  *
96da6c28aaSamw  * - The members of the TOP-MOST construct are scattered through the Stub
97da6c28aaSamw  *   Data in the order they occur.  This example shows a TOP-MOST construct
98da6c28aaSamw  *   consisting of atomic types (pointers and integers).  A construct
99da6c28aaSamw  *   (struct) within the TOP-MOST construct would be contiguous and not
100da6c28aaSamw  *   scattered.
101da6c28aaSamw  *
102da6c28aaSamw  * - The members of OUTER constructs are contiguous, which allows for
103da6c28aaSamw  *   non-copied relocated (fixed-up) data structures at the packet's
104da6c28aaSamw  *   destination.  We don't do fix-ups here.  The pointers within the
105da6c28aaSamw  *   OUTER constructs are processed depth-first in the order that they
106da6c28aaSamw  *   occur.  If they were processed breadth first, the sequence would
107da6c28aaSamw  *   be #1,"foo",#2,"bar".  This is tricky because OUTER constructs may
108da6c28aaSamw  *   be variable length, and pointers are often encountered before the
109da6c28aaSamw  *   size(s) is known.
110da6c28aaSamw  *
111da6c28aaSamw  * - The INNER constructs are simply the members of an OUTER construct.
112da6c28aaSamw  *
113da6c28aaSamw  * For comparison, consider how ONC RPC would handle the same tree of
114da6c28aaSamw  * data.  ONC requires very little buffering, while DCE requires enough
115da6c28aaSamw  * buffer space for the entire message.  ONC does atom-by-atom depth-first
116da6c28aaSamw  * (de)serialization and copy, while DCE allows for constructs to be
117da6c28aaSamw  * "fixed-up" (relocated) in place at the destination.  The packet data
118da6c28aaSamw  * for the same tree processed by ONC RPC would look like this:
119da6c28aaSamw  *
120da6c28aaSamw  *   +---------------------------------------------------------------------+
121da6c28aaSamw  *   |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
122da6c28aaSamw  *   +---------------------------------------------------------------------+
123da6c28aaSamw  *   TOP    #1      #2      #2     bar   #2      #1     foo   #1      TOP
124da6c28aaSamw  *
125da6c28aaSamw  * More details about each TOP-MOST, OUTER, and INNER constructs appear
126da6c28aaSamw  * throughout this source file near where such constructs are processed.
127da6c28aaSamw  *
128da6c28aaSamw  * NDR_REFERENCE
129da6c28aaSamw  *
1308d7e4166Sjose borrego  * The primary object for NDR is the ndr_ref_t.
131da6c28aaSamw  *
1328d7e4166Sjose borrego  * An ndr reference indicates the local datum (i.e. native "C" data
133da6c28aaSamw  * format), and the element within the Stub Data (contained within the
1348d7e4166Sjose borrego  * RPC PDU (protocol data unit).  An ndr reference also indicates,
135da6c28aaSamw  * largely as a debugging aid, something about the type of the
136da6c28aaSamw  * element/datum, and the enclosing construct for the element. The
1378d7e4166Sjose borrego  * ndr reference's are typically allocated on the stack as locals,
1388d7e4166Sjose borrego  * and the chain of ndr-reference.enclosing references is in reverse
139da6c28aaSamw  * order of the call graph.
140da6c28aaSamw  *
1418d7e4166Sjose borrego  * The ndr-reference.datum is a pointer to the local memory that
1428d7e4166Sjose borrego  * contains/receives the value. The ndr-reference.pdu_offset indicates
143da6c28aaSamw  * where in the Stub Data the value is to be stored/retrieved.
144da6c28aaSamw  *
1458d7e4166Sjose borrego  * The ndr-reference also contains various parameters to the NDR
1468d7e4166Sjose borrego  * process, such as ndr-reference.size_is, which indicates the size
1478d7e4166Sjose borrego  * of variable length data, or ndr-reference.switch_is, which
148da6c28aaSamw  * indicates the arm of a union to use.
149da6c28aaSamw  *
150da6c28aaSamw  * QUEUE OF OUTER REFERENCES
151da6c28aaSamw  *
152da6c28aaSamw  * Some OUTER constructs are variable size.  Sometimes (often) we don't
153da6c28aaSamw  * know the size of the OUTER construct until after pointers have been
154da6c28aaSamw  * encountered. Hence, we can not begin processing the referent of the
155da6c28aaSamw  * pointer until after the referring OUTER construct is completely
156da6c28aaSamw  * processed, i.e. we don't know where to find/put the referent in the
157da6c28aaSamw  * Stub Data until we know the size of all its predecessors.
158da6c28aaSamw  *
159da6c28aaSamw  * This is managed using the queue of OUTER references.  The queue is
1608d7e4166Sjose borrego  * anchored in ndr_stream.outer_queue_head.  At any time,
1618d7e4166Sjose borrego  * ndr_stream.outer_queue_tailp indicates where to put the
1628d7e4166Sjose borrego  * ndr-reference for the next encountered pointer.
163da6c28aaSamw  *
164da6c28aaSamw  * Refer to the example above as we illustrate the queue here.  In these
165da6c28aaSamw  * illustrations, the queue entries are not the data structures themselves.
1668d7e4166Sjose borrego  * Rather, they are ndr-reference entries which **refer** to the data
167da6c28aaSamw  * structures in both the PDU and local memory.
168da6c28aaSamw  *
169da6c28aaSamw  * During some point in the processing, the queue looks like this:
170da6c28aaSamw  *
171da6c28aaSamw  *   outer_current -------v
172da6c28aaSamw  *   outer_queue_head --> list#1 --0
173da6c28aaSamw  *   outer_queue_tailp ---------&
174da6c28aaSamw  *
175da6c28aaSamw  * When the pointer #1.next is encountered, and entry is added to the
176da6c28aaSamw  * queue,
177da6c28aaSamw  *
178da6c28aaSamw  *   outer_current -------v
179da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --0
180da6c28aaSamw  *   outer_queue_tailp --------------------&
181da6c28aaSamw  *
182da6c28aaSamw  * and the members of #1 continue to be processed, which encounters
183da6c28aaSamw  * #1.str:
184da6c28aaSamw  *
185da6c28aaSamw  *   outer_current -------v
186da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
187da6c28aaSamw  *   outer_queue_tailp ------------------------------&
188da6c28aaSamw  *
1898d7e4166Sjose borrego  * Upon the completion of list#1, the processing continues by moving to
1908d7e4166Sjose borrego  * ndr_stream.outer_current->next, and the tail is set to this outer member:
191da6c28aaSamw  *
192da6c28aaSamw  *   outer_current ------------------v
193da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
194da6c28aaSamw  *   outer_queue_tailp --------------------&
195da6c28aaSamw  *
196da6c28aaSamw  * Space for list#2 is allocated, either in the Stub Data or of local
197da6c28aaSamw  * memory.  When #2.next is encountered, it is found to be the null
198da6c28aaSamw  * pointer and no reference is added to the queue.  When #2.str is
199da6c28aaSamw  * encountered, it is found to be valid, and a reference is added:
200da6c28aaSamw  *
201da6c28aaSamw  *   outer_current ------------------v
202da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
203da6c28aaSamw  *   outer_queue_tailp ------------------------------&
204da6c28aaSamw  *
205da6c28aaSamw  * Processing continues in a similar fashion with the string "bar",
206da6c28aaSamw  * which is variable-length.  At this point, memory for "bar" may be
207da6c28aaSamw  * malloc()ed during NDR_M_OP_UNMARSHALL:
208da6c28aaSamw  *
209da6c28aaSamw  *   outer_current -----------------------------v
210da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
211da6c28aaSamw  *   outer_queue_tailp ------------------------------&
212da6c28aaSamw  *
213da6c28aaSamw  * And finishes on string "foo".  Notice that because "bar" is a
214da6c28aaSamw  * variable length string, and we don't know the PDU offset for "foo"
215da6c28aaSamw  * until we reach this point.
216da6c28aaSamw  *
217da6c28aaSamw  * When the queue is drained (current->next==0), processing continues
218da6c28aaSamw  * with the next TOP-MOST member.
219da6c28aaSamw  *
220da6c28aaSamw  * The queue of OUTER constructs manages the variable-length semantics
221da6c28aaSamw  * of OUTER constructs and satisfies the depth-first requirement.
222da6c28aaSamw  * We allow the queue to linger until the entire TOP-MOST structure is
223da6c28aaSamw  * processed as an aid to debugging.
224da6c28aaSamw  */
225da6c28aaSamw 
2268d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
2278d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *);
228da6c28aaSamw 
229da6c28aaSamw /*
230da6c28aaSamw  * TOP-MOST ELEMENTS
231da6c28aaSamw  *
232da6c28aaSamw  * This is fundamentally the first OUTER construct of the parameter,
233da6c28aaSamw  * possibly followed by more OUTER constructs due to pointers.  The
234da6c28aaSamw  * datum (local memory) for TOP-MOST constructs (structs) is allocated
235da6c28aaSamw  * by the caller of NDR.
236da6c28aaSamw  *
237da6c28aaSamw  * After the element is transferred, the outer_queue is drained.
238da6c28aaSamw  *
239da6c28aaSamw  * All we have to do is add an entry to the outer_queue for this
240da6c28aaSamw  * top-most member, and commence the outer_queue processing.
241da6c28aaSamw  */
242da6c28aaSamw int
2438d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
244da6c28aaSamw {
2458d7e4166Sjose borrego 	ndr_ref_t	myref;
246da6c28aaSamw 
247da6c28aaSamw 	bzero(&myref, sizeof (myref));
2488d7e4166Sjose borrego 	myref.stream = nds;
249da6c28aaSamw 	myref.datum = datum;
250da6c28aaSamw 	myref.name = "PROCESS";
251da6c28aaSamw 	myref.ti = ti;
252da6c28aaSamw 
2538d7e4166Sjose borrego 	return (ndr_topmost(&myref));
254da6c28aaSamw }
255da6c28aaSamw 
256da6c28aaSamw int
2578d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
258da6c28aaSamw {
2598d7e4166Sjose borrego 	ndr_ref_t	myref;
260da6c28aaSamw 
261da6c28aaSamw 	bzero(&myref, sizeof (myref));
2628d7e4166Sjose borrego 	myref.stream = nds;
263da6c28aaSamw 	myref.datum = datum;
264da6c28aaSamw 	myref.name = "OPERATION";
265da6c28aaSamw 	myref.ti = ti;
266da6c28aaSamw 	myref.inner_flags = NDR_F_SWITCH_IS;
267da6c28aaSamw 	myref.switch_is = opnum;
268da6c28aaSamw 
269da6c28aaSamw 	if (ti->type_flags != NDR_F_INTERFACE) {
270da6c28aaSamw 		NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
271da6c28aaSamw 		return (0);
272da6c28aaSamw 	}
273da6c28aaSamw 
274da6c28aaSamw 	return ((*ti->ndr_func)(&myref));
275da6c28aaSamw }
276da6c28aaSamw 
277da6c28aaSamw int
2788d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref)
279da6c28aaSamw {
2808d7e4166Sjose borrego 	ndr_typeinfo_t *ti = params_ref->ti;
281da6c28aaSamw 
282da6c28aaSamw 	if (ti->type_flags == NDR_F_OPERATION)
283da6c28aaSamw 		return (*ti->ndr_func) (params_ref);
284da6c28aaSamw 	else
2858d7e4166Sjose borrego 		return (ndr_topmost(params_ref));
286da6c28aaSamw }
287da6c28aaSamw 
288da6c28aaSamw int
2898d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref)
290da6c28aaSamw {
2918d7e4166Sjose borrego 	ndr_stream_t *nds;
2928d7e4166Sjose borrego 	ndr_typeinfo_t *ti;
2938d7e4166Sjose borrego 	ndr_ref_t *outer_ref = 0;
294da6c28aaSamw 	int	is_varlen;
295da6c28aaSamw 	int	is_string;
296da6c28aaSamw 	int	error;
297da6c28aaSamw 	int	rc;
298da6c28aaSamw 	unsigned n_fixed;
299da6c28aaSamw 	int	params;
300da6c28aaSamw 
301da6c28aaSamw 	assert(top_ref);
302da6c28aaSamw 	assert(top_ref->stream);
303da6c28aaSamw 	assert(top_ref->ti);
304da6c28aaSamw 
3058d7e4166Sjose borrego 	nds = top_ref->stream;
306da6c28aaSamw 	ti = top_ref->ti;
307da6c28aaSamw 
308da6c28aaSamw 	is_varlen = ti->pdu_size_variable_part;
309da6c28aaSamw 	is_string = NDR_IS_STRING(ti);
310da6c28aaSamw 
3118d7e4166Sjose borrego 	assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
3128d7e4166Sjose borrego 	assert(!nds->outer_current);
313da6c28aaSamw 
314da6c28aaSamw 	params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
315da6c28aaSamw 
316da6c28aaSamw 	switch (params) {
317da6c28aaSamw 	case NDR_F_NONE:
318da6c28aaSamw 	case NDR_F_SWITCH_IS:
319da6c28aaSamw 		if (is_string || is_varlen) {
320da6c28aaSamw 			error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
321da6c28aaSamw 			NDR_SET_ERROR(outer_ref, error);
322da6c28aaSamw 			return (0);
323da6c28aaSamw 		}
324da6c28aaSamw 		n_fixed = ti->pdu_size_fixed_part;
325da6c28aaSamw 		break;
326da6c28aaSamw 
327da6c28aaSamw 	case NDR_F_SIZE_IS:
328da6c28aaSamw 		error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
329da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
330da6c28aaSamw 		return (0);
331da6c28aaSamw 
332da6c28aaSamw 	case NDR_F_DIMENSION_IS:
333da6c28aaSamw 		if (is_varlen) {
334da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
335da6c28aaSamw 			NDR_SET_ERROR(outer_ref, error);
336da6c28aaSamw 			return (0);
337da6c28aaSamw 		}
338da6c28aaSamw 		n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
339da6c28aaSamw 		break;
340da6c28aaSamw 
341da6c28aaSamw 	case NDR_F_IS_POINTER:
342da6c28aaSamw 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
343da6c28aaSamw 		n_fixed = 4;
344da6c28aaSamw 		break;
345da6c28aaSamw 
346da6c28aaSamw 	case NDR_F_IS_REFERENCE:
347da6c28aaSamw 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
348da6c28aaSamw 		n_fixed = 0;
349da6c28aaSamw 		break;
350da6c28aaSamw 
351da6c28aaSamw 	default:
352da6c28aaSamw 		error = NDR_ERR_OUTER_PARAMS_BAD;
353da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
354da6c28aaSamw 		return (0);
355da6c28aaSamw 	}
356da6c28aaSamw 
3578d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(top_ref);
358da6c28aaSamw 	if (!outer_ref)
359da6c28aaSamw 		return (0);	/* error already set */
360da6c28aaSamw 
361da6c28aaSamw 	/*
362da6c28aaSamw 	 * Hand-craft the first OUTER construct and directly call
3638d7e4166Sjose borrego 	 * ndr_inner(). Then, run the outer_queue. We do this
3648d7e4166Sjose borrego 	 * because ndr_outer() wants to malloc() memory for
365da6c28aaSamw 	 * the construct, and we already have the memory.
366da6c28aaSamw 	 */
367da6c28aaSamw 
368da6c28aaSamw 	/* move the flags, etc, around again, undoes enter_outer_queue() */
369da6c28aaSamw 	outer_ref->inner_flags = top_ref->inner_flags;
370da6c28aaSamw 	outer_ref->outer_flags = 0;
371da6c28aaSamw 	outer_ref->datum = top_ref->datum;
372da6c28aaSamw 
373da6c28aaSamw 	/* All outer constructs start on a mod4 (longword) boundary */
3748d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
375da6c28aaSamw 		return (0);		/* error already set */
376da6c28aaSamw 
377da6c28aaSamw 	/* Regardless of what it is, this is where it starts */
3788d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
379da6c28aaSamw 
3808d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_fixed);
381da6c28aaSamw 	if (!rc)
382da6c28aaSamw 		return (0);		/* error already set */
383da6c28aaSamw 
384da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
385da6c28aaSamw 
386da6c28aaSamw 	/* set-up outer_current, as though run_outer_queue() was doing it */
3878d7e4166Sjose borrego 	nds->outer_current = outer_ref;
3888d7e4166Sjose borrego 	nds->outer_queue_tailp = &nds->outer_current->next;
3898d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
390da6c28aaSamw 
391da6c28aaSamw 	/* do the topmost member */
3928d7e4166Sjose borrego 	rc = ndr_inner(outer_ref);
393da6c28aaSamw 	if (!rc)
394da6c28aaSamw 		return (0);		/* error already set */
395da6c28aaSamw 
3968d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
397da6c28aaSamw 
398da6c28aaSamw 	/* advance, as though run_outer_queue() was doing it */
3998d7e4166Sjose borrego 	nds->outer_current = nds->outer_current->next;
4008d7e4166Sjose borrego 	return (ndr_run_outer_queue(nds));
401da6c28aaSamw }
402da6c28aaSamw 
4038d7e4166Sjose borrego static ndr_ref_t *
4048d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref)
405da6c28aaSamw {
4068d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
4078d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
408da6c28aaSamw 
409da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
4108d7e4166Sjose borrego 	outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
411da6c28aaSamw 	if (!outer_ref) {
412da6c28aaSamw 		NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
413da6c28aaSamw 		return (0);
414da6c28aaSamw 	}
415da6c28aaSamw 
416da6c28aaSamw 	*outer_ref = *arg_ref;
417da6c28aaSamw 
418da6c28aaSamw 	/* move advice in inner_flags to outer_flags */
419da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
420da6c28aaSamw 	outer_ref->inner_flags = 0;
4218d7e4166Sjose borrego 	outer_ref->enclosing = nds->outer_current;
422da6c28aaSamw 	outer_ref->backptr = 0;
423da6c28aaSamw 	outer_ref->datum = 0;
424da6c28aaSamw 
4258d7e4166Sjose borrego 	assert(nds->outer_queue_tailp);
426da6c28aaSamw 
4278d7e4166Sjose borrego 	outer_ref->next = *nds->outer_queue_tailp;
4288d7e4166Sjose borrego 	*nds->outer_queue_tailp = outer_ref;
4298d7e4166Sjose borrego 	nds->outer_queue_tailp = &outer_ref->next;
430da6c28aaSamw 	return (outer_ref);
431da6c28aaSamw }
432da6c28aaSamw 
433da6c28aaSamw int
4348d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds)
435da6c28aaSamw {
4368d7e4166Sjose borrego 	while (nds->outer_current) {
4378d7e4166Sjose borrego 		nds->outer_queue_tailp = &nds->outer_current->next;
438da6c28aaSamw 
4398d7e4166Sjose borrego 		if (!ndr_outer(nds->outer_current))
440da6c28aaSamw 			return (0);
441da6c28aaSamw 
4428d7e4166Sjose borrego 		nds->outer_current = nds->outer_current->next;
443da6c28aaSamw 	}
444da6c28aaSamw 
445da6c28aaSamw 	return (1);
446da6c28aaSamw }
447da6c28aaSamw 
448da6c28aaSamw /*
449da6c28aaSamw  * OUTER CONSTRUCTS
450da6c28aaSamw  *
451da6c28aaSamw  * OUTER constructs are where the real work is, which stems from the
452da6c28aaSamw  * variable-length potential.
453da6c28aaSamw  *
454da6c28aaSamw  * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
455da6c28aaSamw  *
456da6c28aaSamw  * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
457da6c28aaSamw  * VARYING, and VARYING/CONFORMANT.
458da6c28aaSamw  *
459da6c28aaSamw  * What makes this so tough is that the variable-length array may be well
460da6c28aaSamw  * encapsulated within the outer construct.  Further, because DCE(MS)/RPC
461da6c28aaSamw  * tries to keep the constructs contiguous in the data stream, the sizing
462da6c28aaSamw  * information precedes the entire OUTER construct.  The sizing information
463da6c28aaSamw  * must be used at the appropriate time, which can be after many, many,
464da6c28aaSamw  * many fixed-length elements.  During IDL type analysis, we know in
465da6c28aaSamw  * advance constructs that encapsulate variable-length constructs.  So,
466da6c28aaSamw  * we know when we have a sizing header and when we don't.  The actual
467da6c28aaSamw  * semantics of the header are largely deferred.
468da6c28aaSamw  *
469da6c28aaSamw  * Currently, VARYING constructs are not implemented but they are described
470da6c28aaSamw  * here in case they have to be implemented in the future.  Similarly,
471da6c28aaSamw  * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
472da6c28aaSamw  * not implemented.  Only one-dimensional, variable-length arrays are
473da6c28aaSamw  * supported.
474da6c28aaSamw  *
475da6c28aaSamw  * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
476da6c28aaSamw  *
477da6c28aaSamw  * All variable-length values are arrays.  These arrays may be embedded
478da6c28aaSamw  * well within another construct.  However, a variable-length construct
479da6c28aaSamw  * may ONLY appear as the last member of an enclosing construct.  Example:
480da6c28aaSamw  *
481da6c28aaSamw  *	struct credentials {
482da6c28aaSamw  *		ulong	uid, gid;
483da6c28aaSamw  *		ulong	n_gids;
484da6c28aaSamw  *	    [size_is(n_gids)]
485da6c28aaSamw  *		ulong	gids[*];    // variable-length.
486da6c28aaSamw  *	};
487da6c28aaSamw  *
488da6c28aaSamw  * CONFORMANT constructs have a dynamic size in local memory and in the
489da6c28aaSamw  * PDU.  The CONFORMANT quality is indicated by the [size_is()] advice.
490da6c28aaSamw  * CONFORMANT constructs have the following header:
491da6c28aaSamw  *
492da6c28aaSamw  *	struct conformant_header {
493da6c28aaSamw  *		ulong		size_is;
494da6c28aaSamw  *	};
495da6c28aaSamw  *
496da6c28aaSamw  * (Multi-dimensional CONFORMANT arrays have a similar header for each
497da6c28aaSamw  * dimension - not implemented).
498da6c28aaSamw  *
499da6c28aaSamw  * Example CONFORMANT construct:
500da6c28aaSamw  *
501da6c28aaSamw  *	struct user {
502da6c28aaSamw  *		char *			name;
503da6c28aaSamw  *		struct credentials	cred;	// see above
504da6c28aaSamw  *	};
505da6c28aaSamw  *
506da6c28aaSamw  * Consider the data tree:
507da6c28aaSamw  *
508da6c28aaSamw  *    +--------+
509da6c28aaSamw  *    |  user  |
510da6c28aaSamw  *    +--------+
511da6c28aaSamw  *    | name  ----> "fred" (the string is a different OUTER)
512da6c28aaSamw  *    | uid    |
513da6c28aaSamw  *    | gid    |
514da6c28aaSamw  *    | n_gids |    for example, 3
515da6c28aaSamw  *    | gids[0]|
516da6c28aaSamw  *    | gids[1]|
517da6c28aaSamw  *    | gids[2]|
518da6c28aaSamw  *    +--------+
519da6c28aaSamw  *
520da6c28aaSamw  * The OUTER construct in the Stub Data would be:
521da6c28aaSamw  *
522da6c28aaSamw  *    +---+---------+---------------------------------------------+
523da6c28aaSamw  *    |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
524da6c28aaSamw  *    +---+---------+---------------------------------------------+
525da6c28aaSamw  *         szing hdr|user |<-------------- user.cred ------------>|
526da6c28aaSamw  *                  |<--- fixed-size ---->|<----- conformant ---->|
527da6c28aaSamw  *
528da6c28aaSamw  * The ndr_typeinfo for struct user will have:
529da6c28aaSamw  *	pdu_fixed_size_part = 16	four long words (name uid gid n_gids)
530da6c28aaSamw  *	pdu_variable_size_part = 4	per element, sizeof gids[0]
531da6c28aaSamw  *
532da6c28aaSamw  * VARYING CONSTRUCTS -- NOT IMPLEMENTED
533da6c28aaSamw  *
534da6c28aaSamw  * VARYING constructs have the following header:
535da6c28aaSamw  *
536da6c28aaSamw  *	struct varying_header {
537da6c28aaSamw  *		ulong		first_is;
538da6c28aaSamw  *		ulong		length_is;
539da6c28aaSamw  *	};
540da6c28aaSamw  *
541da6c28aaSamw  * This indicates which interval of an array is significant.
542da6c28aaSamw  * Non-intersecting elements of the array are undefined and usually
543da6c28aaSamw  * zero-filled.  The first_is parameter for C arrays is always 0 for
544da6c28aaSamw  * the first element.
545da6c28aaSamw  *
546da6c28aaSamw  * N.B. Constructs may contain one CONFORMANT element, which is always
547da6c28aaSamw  * last, but may contain many VARYING elements, which can be anywhere.
548da6c28aaSamw  *
549da6c28aaSamw  * VARYING CONFORMANT constructs have the sizing headers arranged like
550da6c28aaSamw  * this:
551da6c28aaSamw  *
552da6c28aaSamw  *	struct conformant_header	all_conformant[N_CONFORMANT_DIM];
553da6c28aaSamw  *	struct varying_header		all_varying[N_VARYING_ELEMS_AND_DIMS];
554da6c28aaSamw  *
555da6c28aaSamw  * The sizing header is immediately followed by the values for the
556da6c28aaSamw  * construct.  Again, we don't support more than one dimension and
557da6c28aaSamw  * we don't support VARYING constructs at this time.
558da6c28aaSamw  *
559da6c28aaSamw  * A good example of a VARYING/CONFORMANT data structure is the UNIX
560da6c28aaSamw  * directory entry:
561da6c28aaSamw  *
562da6c28aaSamw  *	struct dirent {
563da6c28aaSamw  *		ushort		reclen;
564da6c28aaSamw  *		ushort		namlen;
565da6c28aaSamw  *		ulong		inum;
566da6c28aaSamw  *	    [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
567da6c28aaSamw  *		uchar		name[*];
568da6c28aaSamw  *	};
569da6c28aaSamw  *
570da6c28aaSamw  *
571da6c28aaSamw  * STRINGS ARE A SPECIAL CASE
572da6c28aaSamw  *
573da6c28aaSamw  * Strings are handled specially.  MS/RPC uses VARYING/CONFORMANT structures
574da6c28aaSamw  * for strings.  This is a simple one-dimensional variable-length array,
575da6c28aaSamw  * typically with its last element all zeroes.  We handle strings with the
576da6c28aaSamw  * header:
577da6c28aaSamw  *
578da6c28aaSamw  *	struct string_header {
579da6c28aaSamw  *		ulong		size_is;
580da6c28aaSamw  *		ulong		first_is;	// always 0
581da6c28aaSamw  *		ulong		length_is;	// always same as size_is
582da6c28aaSamw  *	};
583da6c28aaSamw  *
584da6c28aaSamw  * If general support for VARYING and VARYING/CONFORMANT mechanisms is
585da6c28aaSamw  * implemented, we probably won't need the strings special case.
586da6c28aaSamw  */
587da6c28aaSamw int
5888d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref)
589da6c28aaSamw {
590*1ca4e8dfSGordon Ross 	ndr_stream_t	*nds = outer_ref->stream;
5918d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
592da6c28aaSamw 	int	is_varlen = ti->pdu_size_variable_part;
593da6c28aaSamw 	int	is_union = NDR_IS_UNION(ti);
594da6c28aaSamw 	int	is_string = NDR_IS_STRING(ti);
595da6c28aaSamw 	int	error = NDR_ERR_OUTER_PARAMS_BAD;
596da6c28aaSamw 	int	params;
597da6c28aaSamw 
598da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
599da6c28aaSamw 
600da6c28aaSamw 	NDR_TATTLE(outer_ref, "--OUTER--");
601da6c28aaSamw 
602da6c28aaSamw 	/* All outer constructs start on a mod4 (longword) boundary */
6038d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
604da6c28aaSamw 		return (0);		/* error already set */
605da6c28aaSamw 
606da6c28aaSamw 	/* Regardless of what it is, this is where it starts */
6078d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
608da6c28aaSamw 
609da6c28aaSamw 	if (is_union) {
610da6c28aaSamw 		error = NDR_ERR_OUTER_UNION_ILLEGAL;
611da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
612da6c28aaSamw 		return (0);
613da6c28aaSamw 	}
614da6c28aaSamw 
615da6c28aaSamw 	switch (params) {
616da6c28aaSamw 	case NDR_F_NONE:
617da6c28aaSamw 		if (is_string)
6188d7e4166Sjose borrego 			return (ndr_outer_string(outer_ref));
619da6c28aaSamw 		if (is_varlen)
6208d7e4166Sjose borrego 			return (ndr_outer_conformant_construct(outer_ref));
621da6c28aaSamw 
6228d7e4166Sjose borrego 		return (ndr_outer_fixed(outer_ref));
623da6c28aaSamw 
624da6c28aaSamw 	case NDR_F_SIZE_IS:
625da6c28aaSamw 	case NDR_F_DIMENSION_IS:
626f96bd5c8SAlan Wright 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
627f96bd5c8SAlan Wright 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
628da6c28aaSamw 		if (is_varlen) {
629da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
630da6c28aaSamw 			break;
631da6c28aaSamw 		}
632da6c28aaSamw 
633f96bd5c8SAlan Wright 		if (params & NDR_F_SIZE_IS)
6348d7e4166Sjose borrego 			return (ndr_outer_conformant_array(outer_ref));
635da6c28aaSamw 		else
6368d7e4166Sjose borrego 			return (ndr_outer_fixed_array(outer_ref));
637da6c28aaSamw 
638da6c28aaSamw 	default:
639da6c28aaSamw 		error = NDR_ERR_OUTER_PARAMS_BAD;
640da6c28aaSamw 		break;
641da6c28aaSamw 	}
642da6c28aaSamw 
643da6c28aaSamw 	/*
644da6c28aaSamw 	 * If we get here, something is wrong. Most likely,
645da6c28aaSamw 	 * the params flags do not match.
646da6c28aaSamw 	 */
647da6c28aaSamw 	NDR_SET_ERROR(outer_ref, error);
648da6c28aaSamw 	return (0);
649da6c28aaSamw }
650da6c28aaSamw 
651da6c28aaSamw int
6528d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref)
653da6c28aaSamw {
6548d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
6558d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
6568d7e4166Sjose borrego 	ndr_ref_t	myref;
657*1ca4e8dfSGordon Ross 	char		*valp = NULL;
658da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
659da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
660da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
661da6c28aaSamw 	int		rc;
662da6c28aaSamw 	unsigned	n_hdr;
663da6c28aaSamw 	unsigned	n_fixed;
664da6c28aaSamw 	unsigned	n_variable;
665da6c28aaSamw 	unsigned	n_alloc;
666da6c28aaSamw 	unsigned	n_pdu_total;
667da6c28aaSamw 	int		params;
668da6c28aaSamw 
669da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
670da6c28aaSamw 
671da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
672da6c28aaSamw 	assert(params == NDR_F_NONE);
673da6c28aaSamw 
674da6c28aaSamw 	/* no header for this */
675da6c28aaSamw 	n_hdr = 0;
676da6c28aaSamw 
677da6c28aaSamw 	/* fixed part -- exactly one of these */
678da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
679da6c28aaSamw 	assert(n_fixed > 0);
680da6c28aaSamw 
681da6c28aaSamw 	/* variable part -- exactly none of these */
682da6c28aaSamw 	n_variable = 0;
683da6c28aaSamw 
684da6c28aaSamw 	/* sum them up to determine the PDU space required */
685da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
686da6c28aaSamw 
687da6c28aaSamw 	/* similar sum to determine how much local memory is required */
688da6c28aaSamw 	n_alloc = n_fixed + n_variable;
689da6c28aaSamw 
6908d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
691da6c28aaSamw 	if (!rc)
692da6c28aaSamw 		return (rc);		/* error already set */
693da6c28aaSamw 
6948d7e4166Sjose borrego 	switch (nds->m_op) {
695da6c28aaSamw 	case NDR_M_OP_MARSHALL:
696da6c28aaSamw 		valp = outer_ref->datum;
69796a62adaSjoyce mcintosh 		if (!valp) {
69896a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
69996a62adaSjoyce mcintosh 			return (0);
70096a62adaSjoyce mcintosh 		}
701f96bd5c8SAlan Wright 		if (outer_ref->backptr)
702da6c28aaSamw 			assert(valp == *outer_ref->backptr);
703da6c28aaSamw 		break;
704da6c28aaSamw 
705da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
7068d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
707da6c28aaSamw 		if (!valp) {
708da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
709da6c28aaSamw 			return (0);
710da6c28aaSamw 		}
711da6c28aaSamw 		if (outer_ref->backptr)
712da6c28aaSamw 			*outer_ref->backptr = valp;
713da6c28aaSamw 		outer_ref->datum = valp;
714da6c28aaSamw 		break;
715da6c28aaSamw 
716da6c28aaSamw 	default:
717da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
718da6c28aaSamw 		return (0);
719da6c28aaSamw 	}
720da6c28aaSamw 
721da6c28aaSamw 	bzero(&myref, sizeof (myref));
7228d7e4166Sjose borrego 	myref.stream = nds;
723da6c28aaSamw 	myref.enclosing = outer_ref;
724da6c28aaSamw 	myref.ti = outer_ref->ti;
725da6c28aaSamw 	myref.datum = outer_ref->datum;
726da6c28aaSamw 	myref.name = "FIXED-VALUE";
727da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
728da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
729da6c28aaSamw 
730da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset;
731da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
732da6c28aaSamw 
7338d7e4166Sjose borrego 	rc = ndr_inner(&myref);
734da6c28aaSamw 	if (!rc)
735da6c28aaSamw 		return (rc);		/* error already set */
736da6c28aaSamw 
7378d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
738da6c28aaSamw 	return (1);
739da6c28aaSamw }
740da6c28aaSamw 
741da6c28aaSamw int
7428d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref)
743da6c28aaSamw {
7448d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
7458d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
7468d7e4166Sjose borrego 	ndr_ref_t	myref;
747*1ca4e8dfSGordon Ross 	char		*valp = NULL;
748da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
749da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
750da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
751da6c28aaSamw 	int		rc;
752da6c28aaSamw 	unsigned	n_hdr;
753da6c28aaSamw 	unsigned	n_fixed;
754da6c28aaSamw 	unsigned	n_variable;
755da6c28aaSamw 	unsigned	n_alloc;
756da6c28aaSamw 	unsigned	n_pdu_total;
757da6c28aaSamw 	int		params;
758da6c28aaSamw 
759da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
760da6c28aaSamw 
761da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
762da6c28aaSamw 	assert(params == NDR_F_DIMENSION_IS);
763da6c28aaSamw 
764da6c28aaSamw 	/* no header for this */
765da6c28aaSamw 	n_hdr = 0;
766da6c28aaSamw 
767da6c28aaSamw 	/* fixed part -- exactly dimension_is of these */
768da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
769da6c28aaSamw 	assert(n_fixed > 0);
770da6c28aaSamw 
771da6c28aaSamw 	/* variable part -- exactly none of these */
772da6c28aaSamw 	n_variable = 0;
773da6c28aaSamw 
774da6c28aaSamw 	/* sum them up to determine the PDU space required */
775da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
776da6c28aaSamw 
777da6c28aaSamw 	/* similar sum to determine how much local memory is required */
778da6c28aaSamw 	n_alloc = n_fixed + n_variable;
779da6c28aaSamw 
7808d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
781da6c28aaSamw 	if (!rc)
782da6c28aaSamw 		return (rc);		/* error already set */
783da6c28aaSamw 
7848d7e4166Sjose borrego 	switch (nds->m_op) {
785da6c28aaSamw 	case NDR_M_OP_MARSHALL:
786da6c28aaSamw 		valp = outer_ref->datum;
78796a62adaSjoyce mcintosh 		if (!valp) {
78896a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
78996a62adaSjoyce mcintosh 			return (0);
79096a62adaSjoyce mcintosh 		}
791f96bd5c8SAlan Wright 		if (outer_ref->backptr)
792da6c28aaSamw 			assert(valp == *outer_ref->backptr);
793da6c28aaSamw 		break;
794da6c28aaSamw 
795da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
7968d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
797da6c28aaSamw 		if (!valp) {
798da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
799da6c28aaSamw 			return (0);
800da6c28aaSamw 		}
801da6c28aaSamw 		if (outer_ref->backptr)
802da6c28aaSamw 			*outer_ref->backptr = valp;
803da6c28aaSamw 		outer_ref->datum = valp;
804da6c28aaSamw 		break;
805da6c28aaSamw 
806da6c28aaSamw 	default:
807da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
808da6c28aaSamw 		return (0);
809da6c28aaSamw 	}
810da6c28aaSamw 
811da6c28aaSamw 	bzero(&myref, sizeof (myref));
8128d7e4166Sjose borrego 	myref.stream = nds;
813da6c28aaSamw 	myref.enclosing = outer_ref;
814da6c28aaSamw 	myref.ti = outer_ref->ti;
815da6c28aaSamw 	myref.datum = outer_ref->datum;
816da6c28aaSamw 	myref.name = "FIXED-ARRAY";
817da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
818da6c28aaSamw 	myref.inner_flags = NDR_F_DIMENSION_IS;
819da6c28aaSamw 	myref.dimension_is = outer_ref->dimension_is;
820da6c28aaSamw 
821da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset;
822da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
823da6c28aaSamw 
8248d7e4166Sjose borrego 	rc = ndr_inner(&myref);
825da6c28aaSamw 	if (!rc)
826da6c28aaSamw 		return (rc);		/* error already set */
827da6c28aaSamw 
8288d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
829da6c28aaSamw 	return (1);
830da6c28aaSamw }
831da6c28aaSamw 
832da6c28aaSamw int
8338d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref)
834da6c28aaSamw {
8358d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
8368d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
8378d7e4166Sjose borrego 	ndr_ref_t	myref;
838*1ca4e8dfSGordon Ross 	char		*valp = NULL;
839da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
840da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
841da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
842da6c28aaSamw 	unsigned long	size_is;
843da6c28aaSamw 	int		rc;
844da6c28aaSamw 	unsigned	n_hdr;
845da6c28aaSamw 	unsigned	n_fixed;
846da6c28aaSamw 	unsigned	n_variable;
847da6c28aaSamw 	unsigned	n_alloc;
848da6c28aaSamw 	unsigned	n_pdu_total;
849f96bd5c8SAlan Wright 	unsigned	n_ptr_offset;
850da6c28aaSamw 	int		params;
851da6c28aaSamw 
852da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
853da6c28aaSamw 
854da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
855f96bd5c8SAlan Wright 	assert(params & NDR_F_SIZE_IS);
856da6c28aaSamw 
857da6c28aaSamw 	/* conformant header for this */
858da6c28aaSamw 	n_hdr = 4;
859da6c28aaSamw 
860da6c28aaSamw 	/* fixed part -- exactly none of these */
861da6c28aaSamw 	n_fixed = 0;
862da6c28aaSamw 
863da6c28aaSamw 	/* variable part -- exactly size_of of these */
864da6c28aaSamw 	/* notice that it is the **fixed** size of the ti */
865da6c28aaSamw 	n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
866da6c28aaSamw 
867da6c28aaSamw 	/* sum them up to determine the PDU space required */
868da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
869da6c28aaSamw 
870da6c28aaSamw 	/* similar sum to determine how much local memory is required */
871da6c28aaSamw 	n_alloc = n_fixed + n_variable;
872da6c28aaSamw 
8738d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
874da6c28aaSamw 	if (!rc)
875da6c28aaSamw 		return (rc);		/* error already set */
876da6c28aaSamw 
8778d7e4166Sjose borrego 	switch (nds->m_op) {
878da6c28aaSamw 	case NDR_M_OP_MARSHALL:
879da6c28aaSamw 		size_is = outer_ref->size_is;
8808d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
881da6c28aaSamw 		if (!rc)
882da6c28aaSamw 			return (0);	/* error already set */
883da6c28aaSamw 
884da6c28aaSamw 		valp = outer_ref->datum;
88596a62adaSjoyce mcintosh 		if (!valp) {
88696a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
88796a62adaSjoyce mcintosh 			return (0);
88896a62adaSjoyce mcintosh 		}
889f96bd5c8SAlan Wright 		if (outer_ref->backptr)
890da6c28aaSamw 			assert(valp == *outer_ref->backptr);
891f96bd5c8SAlan Wright 		n_ptr_offset = 4;
892da6c28aaSamw 		break;
893da6c28aaSamw 
894da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
895f96bd5c8SAlan Wright 		if (params & NDR_F_IS_REFERENCE) {
896f96bd5c8SAlan Wright 			size_is = outer_ref->size_is;
897f96bd5c8SAlan Wright 			n_ptr_offset = 0;
898f96bd5c8SAlan Wright 		} else {
899f96bd5c8SAlan Wright 			/* NDR_F_IS_POINTER */
900f96bd5c8SAlan Wright 			rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
901f96bd5c8SAlan Wright 			if (!rc)
902f96bd5c8SAlan Wright 				return (0);	/* error already set */
903f96bd5c8SAlan Wright 
904f96bd5c8SAlan Wright 			if (size_is != outer_ref->size_is) {
905f96bd5c8SAlan Wright 				NDR_SET_ERROR(outer_ref,
906f96bd5c8SAlan Wright 				    NDR_ERR_SIZE_IS_MISMATCH_PDU);
907f96bd5c8SAlan Wright 				return (0);
908f96bd5c8SAlan Wright 			}
909da6c28aaSamw 
910f96bd5c8SAlan Wright 			n_ptr_offset = 4;
911da6c28aaSamw 		}
912da6c28aaSamw 
9133ad684d6Sjb 		if (size_is > 0) {
9148d7e4166Sjose borrego 			valp = NDS_MALLOC(nds, n_alloc, outer_ref);
9153ad684d6Sjb 			if (!valp) {
9163ad684d6Sjb 				NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
9173ad684d6Sjb 				return (0);
9183ad684d6Sjb 			}
919da6c28aaSamw 		}
9203ad684d6Sjb 
921da6c28aaSamw 		if (outer_ref->backptr)
922da6c28aaSamw 			*outer_ref->backptr = valp;
923da6c28aaSamw 		outer_ref->datum = valp;
924da6c28aaSamw 		break;
925da6c28aaSamw 
926da6c28aaSamw 	default:
927da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
928da6c28aaSamw 		return (0);
929da6c28aaSamw 	}
930da6c28aaSamw 
931da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
932da6c28aaSamw 	outer_ref->type_flags = NDR_F_NONE;
933da6c28aaSamw 	outer_ref->inner_flags = NDR_F_NONE;
934da6c28aaSamw 
9353ad684d6Sjb 	if (size_is > 0) {
9363ad684d6Sjb 		bzero(&myref, sizeof (myref));
9378d7e4166Sjose borrego 		myref.stream = nds;
9383ad684d6Sjb 		myref.enclosing = outer_ref;
9393ad684d6Sjb 		myref.ti = outer_ref->ti;
9403ad684d6Sjb 		myref.datum = outer_ref->datum;
9413ad684d6Sjb 		myref.name = "CONFORMANT-ARRAY";
9423ad684d6Sjb 		myref.outer_flags = NDR_F_NONE;
9433ad684d6Sjb 		myref.inner_flags = NDR_F_SIZE_IS;
9443ad684d6Sjb 		myref.size_is = outer_ref->size_is;
9453ad684d6Sjb 
9463ad684d6Sjb 		myref.inner_flags = NDR_F_DIMENSION_IS;		/* convenient */
9473ad684d6Sjb 		myref.dimension_is = outer_ref->size_is;	/* convenient */
9483ad684d6Sjb 
949f96bd5c8SAlan Wright 		myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
9503ad684d6Sjb 
9518d7e4166Sjose borrego 		rc = ndr_inner(&myref);
9523ad684d6Sjb 		if (!rc)
9533ad684d6Sjb 			return (rc);		/* error already set */
9543ad684d6Sjb 	}
955da6c28aaSamw 
9568d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
957da6c28aaSamw 	return (1);
958da6c28aaSamw }
959da6c28aaSamw 
960da6c28aaSamw int
9618d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
962da6c28aaSamw {
9638d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
9648d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
9658d7e4166Sjose borrego 	ndr_ref_t	myref;
966*1ca4e8dfSGordon Ross 	char		*valp = NULL;
967da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
968da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
969da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
970da6c28aaSamw 	unsigned long	size_is;
971da6c28aaSamw 	int		rc;
972da6c28aaSamw 	unsigned	n_hdr;
973da6c28aaSamw 	unsigned	n_fixed;
974da6c28aaSamw 	unsigned	n_variable;
975da6c28aaSamw 	unsigned	n_alloc;
976da6c28aaSamw 	unsigned	n_pdu_total;
977da6c28aaSamw 	int		params;
978da6c28aaSamw 
979da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
980da6c28aaSamw 
981da6c28aaSamw 	assert(is_varlen && !is_string && !is_union);
982da6c28aaSamw 	assert(params == NDR_F_NONE);
983da6c28aaSamw 
984da6c28aaSamw 	/* conformant header for this */
985da6c28aaSamw 	n_hdr = 4;
986da6c28aaSamw 
987da6c28aaSamw 	/* fixed part -- exactly one of these */
988da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
989da6c28aaSamw 
990da6c28aaSamw 	/* variable part -- exactly size_of of these */
991da6c28aaSamw 	n_variable = 0;		/* 0 for the moment */
992da6c28aaSamw 
993da6c28aaSamw 	/* sum them up to determine the PDU space required */
994da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
995da6c28aaSamw 
996da6c28aaSamw 	/* similar sum to determine how much local memory is required */
997da6c28aaSamw 	n_alloc = n_fixed + n_variable;
998da6c28aaSamw 
999da6c28aaSamw 	/* For the moment, grow enough for the fixed-size part */
10008d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1001da6c28aaSamw 	if (!rc)
1002da6c28aaSamw 		return (rc);		/* error already set */
1003da6c28aaSamw 
10048d7e4166Sjose borrego 	switch (nds->m_op) {
1005da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1006da6c28aaSamw 		/*
1007da6c28aaSamw 		 * We don't know the size yet. We have to wait for
1008da6c28aaSamw 		 * it. Proceed with the fixed-size part, and await
10098d7e4166Sjose borrego 		 * the call to ndr_size_is().
1010da6c28aaSamw 		 */
1011da6c28aaSamw 		size_is = 0;
10128d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1013da6c28aaSamw 		if (!rc)
1014da6c28aaSamw 			return (0);	/* error already set */
1015da6c28aaSamw 
1016da6c28aaSamw 		valp = outer_ref->datum;
101796a62adaSjoyce mcintosh 		if (!valp) {
101896a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
101996a62adaSjoyce mcintosh 			return (0);
102096a62adaSjoyce mcintosh 		}
1021f96bd5c8SAlan Wright 		if (outer_ref->backptr)
1022da6c28aaSamw 			assert(valp == *outer_ref->backptr);
1023da6c28aaSamw 		break;
1024da6c28aaSamw 
1025da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1026da6c28aaSamw 		/*
1027da6c28aaSamw 		 * We know the size of the variable part because
1028da6c28aaSamw 		 * of the CONFORMANT header. We will verify
1029da6c28aaSamw 		 * the header against the [size_is(X)] advice
10308d7e4166Sjose borrego 		 * later when ndr_size_is() is called.
1031da6c28aaSamw 		 */
10328d7e4166Sjose borrego 		rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
1033da6c28aaSamw 		if (!rc)
1034da6c28aaSamw 			return (0);	/* error already set */
1035da6c28aaSamw 
1036da6c28aaSamw 		/* recalculate metrics */
1037da6c28aaSamw 		n_variable = size_is * ti->pdu_size_variable_part;
1038da6c28aaSamw 		n_pdu_total = n_hdr + n_fixed + n_variable;
1039da6c28aaSamw 		n_alloc = n_fixed + n_variable;
1040da6c28aaSamw 
10418d7e4166Sjose borrego 		rc = ndr_outer_grow(outer_ref, n_pdu_total);
1042da6c28aaSamw 		if (!rc)
1043da6c28aaSamw 			return (rc);		/* error already set */
1044da6c28aaSamw 
1045da6c28aaSamw 		outer_ref->size_is = size_is; /* verified later */
1046da6c28aaSamw 
10478d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1048da6c28aaSamw 		if (!valp) {
1049da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1050da6c28aaSamw 			return (0);
1051da6c28aaSamw 		}
1052da6c28aaSamw 		if (outer_ref->backptr)
1053da6c28aaSamw 			*outer_ref->backptr = valp;
1054da6c28aaSamw 		outer_ref->datum = valp;
1055da6c28aaSamw 		break;
1056da6c28aaSamw 
1057da6c28aaSamw 	default:
1058da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1059da6c28aaSamw 		return (0);
1060da6c28aaSamw 	}
1061da6c28aaSamw 
10623ad684d6Sjb 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
10633ad684d6Sjb 	outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
10643ad684d6Sjb 	outer_ref->inner_flags = NDR_F_NONE;   /* indicate pending */
10653ad684d6Sjb 
1066da6c28aaSamw 	bzero(&myref, sizeof (myref));
10678d7e4166Sjose borrego 	myref.stream = nds;
1068da6c28aaSamw 	myref.enclosing = outer_ref;
1069da6c28aaSamw 	myref.ti = outer_ref->ti;
1070da6c28aaSamw 	myref.datum = outer_ref->datum;
1071da6c28aaSamw 	myref.name = "CONFORMANT-CONSTRUCT";
1072da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
1073da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1074da6c28aaSamw 	myref.size_is = outer_ref->size_is;
1075da6c28aaSamw 
1076da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset + 4;
1077da6c28aaSamw 
10788d7e4166Sjose borrego 	rc = ndr_inner(&myref);
1079da6c28aaSamw 	if (!rc)
1080da6c28aaSamw 		return (rc);		/* error already set */
1081da6c28aaSamw 
10828d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1083da6c28aaSamw 
1084da6c28aaSamw 	if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
1085da6c28aaSamw 		NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
1086da6c28aaSamw 		return (0);
1087da6c28aaSamw 	}
1088da6c28aaSamw 
1089da6c28aaSamw 	return (1);
1090da6c28aaSamw }
1091da6c28aaSamw 
1092da6c28aaSamw int
10938d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref)
1094da6c28aaSamw {
1095*1ca4e8dfSGordon Ross 	ndr_stream_t		*nds = ref->stream;
1096*1ca4e8dfSGordon Ross 	ndr_ref_t		*outer_ref = nds->outer_current;
10978d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = outer_ref->ti;
1098da6c28aaSamw 	unsigned long		size_is;
1099da6c28aaSamw 	int			rc;
1100da6c28aaSamw 	unsigned		n_hdr;
1101da6c28aaSamw 	unsigned		n_fixed;
1102da6c28aaSamw 	unsigned		n_variable;
1103da6c28aaSamw 	unsigned		n_pdu_total;
1104da6c28aaSamw 
1105da6c28aaSamw 	assert(ref->inner_flags & NDR_F_SIZE_IS);
1106da6c28aaSamw 	size_is = ref->size_is;
1107da6c28aaSamw 
1108da6c28aaSamw 	if (outer_ref->type_flags != NDR_F_SIZE_IS) {
1109da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
1110da6c28aaSamw 		return (0);
1111da6c28aaSamw 	}
1112da6c28aaSamw 
1113da6c28aaSamw 	if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
1114da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
1115da6c28aaSamw 		return (0);
1116da6c28aaSamw 	}
1117da6c28aaSamw 
11188d7e4166Sjose borrego 	/* repeat metrics, see ndr_conformant_construct() above */
1119da6c28aaSamw 	n_hdr = 4;
1120da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
1121da6c28aaSamw 	n_variable = size_is * ti->pdu_size_variable_part;
1122da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
1123da6c28aaSamw 
11248d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1125da6c28aaSamw 	if (!rc)
1126da6c28aaSamw 		return (rc);		/* error already set */
1127da6c28aaSamw 
11288d7e4166Sjose borrego 	switch (nds->m_op) {
1129da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1130da6c28aaSamw 		/*
1131da6c28aaSamw 		 * We have to set the sizing header and extend
1132da6c28aaSamw 		 * the size of the PDU (already done).
1133da6c28aaSamw 		 */
11348d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1135da6c28aaSamw 		if (!rc)
1136da6c28aaSamw 			return (0);	/* error already set */
1137da6c28aaSamw 		break;
1138da6c28aaSamw 
1139da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1140da6c28aaSamw 		/*
11418d7e4166Sjose borrego 		 * Allocation done during ndr_conformant_construct().
1142da6c28aaSamw 		 * All we are doing here is verifying that the
1143da6c28aaSamw 		 * intended size (ref->size_is) matches the sizing header.
1144da6c28aaSamw 		 */
1145da6c28aaSamw 		if (size_is != outer_ref->size_is) {
1146da6c28aaSamw 			NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
1147da6c28aaSamw 			return (0);
1148da6c28aaSamw 		}
1149da6c28aaSamw 		break;
1150da6c28aaSamw 
1151da6c28aaSamw 	default:
1152da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1153da6c28aaSamw 		return (0);
1154da6c28aaSamw 	}
1155da6c28aaSamw 
1156da6c28aaSamw 	outer_ref->inner_flags |= NDR_F_SIZE_IS;
1157da6c28aaSamw 	outer_ref->size_is = ref->size_is;
1158da6c28aaSamw 	return (1);
1159da6c28aaSamw }
1160da6c28aaSamw 
1161da6c28aaSamw int
11628d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref)
1163da6c28aaSamw {
11648d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
1165*1ca4e8dfSGordon Ross 	ndr_typeinfo_t	*ti = outer_ref->ti;
11668d7e4166Sjose borrego 	ndr_ref_t	myref;
1167*1ca4e8dfSGordon Ross 	char		*valp = NULL;
1168da6c28aaSamw 	unsigned	is_varlen = ti->pdu_size_variable_part;
1169da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
1170da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
1171da6c28aaSamw 	int		rc;
1172da6c28aaSamw 	unsigned	n_zeroes;
1173da6c28aaSamw 	unsigned	ix;
1174da6c28aaSamw 	unsigned long	size_is;
1175da6c28aaSamw 	unsigned long	first_is;
1176da6c28aaSamw 	unsigned long	length_is;
1177da6c28aaSamw 	unsigned	n_hdr;
1178da6c28aaSamw 	unsigned	n_fixed;
1179da6c28aaSamw 	unsigned	n_variable;
1180da6c28aaSamw 	unsigned	n_alloc;
1181da6c28aaSamw 	unsigned	n_pdu_total;
1182da6c28aaSamw 	int		params;
1183da6c28aaSamw 
1184da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1185da6c28aaSamw 
1186da6c28aaSamw 	assert(is_varlen && is_string && !is_union);
1187da6c28aaSamw 	assert(params == NDR_F_NONE);
1188da6c28aaSamw 
1189da6c28aaSamw 	/* string header for this: size_is first_is length_is */
1190da6c28aaSamw 	n_hdr = 12;
1191da6c28aaSamw 
1192da6c28aaSamw 	/* fixed part -- exactly none of these */
1193da6c28aaSamw 	n_fixed = 0;
1194da6c28aaSamw 
11958d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_hdr))
1196da6c28aaSamw 		return (0);		/* error already set */
1197da6c28aaSamw 
11988d7e4166Sjose borrego 	switch (nds->m_op) {
1199da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1200da6c28aaSamw 		valp = outer_ref->datum;
120196a62adaSjoyce mcintosh 		if (!valp) {
120296a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
120396a62adaSjoyce mcintosh 			return (0);
120496a62adaSjoyce mcintosh 		}
1205da6c28aaSamw 
1206da6c28aaSamw 		if (outer_ref->backptr)
1207da6c28aaSamw 			assert(valp == *outer_ref->backptr);
1208da6c28aaSamw 
1209da6c28aaSamw 		if (ti == &ndt_s_wchar) {
1210da6c28aaSamw 			/*
1211a0aa776eSAlan Wright 			 * size_is is the number of characters in the
1212a0aa776eSAlan Wright 			 * (multibyte) string, including the null.
12133299f39fSGordon Ross 			 * In other words, symbols, not bytes.
1214da6c28aaSamw 			 */
12153299f39fSGordon Ross 			size_t wlen;
12163299f39fSGordon Ross 			wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
12173299f39fSGordon Ross 			if (wlen == (size_t)-1) {
12183299f39fSGordon Ross 				/* illegal sequence error? */
1219da6c28aaSamw 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1220da6c28aaSamw 				return (0);
1221da6c28aaSamw 			}
12223299f39fSGordon Ross 			if ((nds->flags & NDS_F_NONULL) == 0)
12233299f39fSGordon Ross 				wlen++;
12243299f39fSGordon Ross 			if (wlen > NDR_STRING_MAX) {
12253299f39fSGordon Ross 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
12263299f39fSGordon Ross 				return (0);
12273299f39fSGordon Ross 			}
12283299f39fSGordon Ross 			size_is = wlen;
1229da6c28aaSamw 		} else {
1230da6c28aaSamw 			valp = outer_ref->datum;
1231da6c28aaSamw 			n_zeroes = 0;
1232f96bd5c8SAlan Wright 			for (ix = 0; ix < NDR_STRING_MAX; ix++) {
1233da6c28aaSamw 				if (valp[ix] == 0) {
1234da6c28aaSamw 					n_zeroes++;
1235da6c28aaSamw 					if (n_zeroes >= is_varlen &&
1236da6c28aaSamw 					    ix % is_varlen == 0) {
1237da6c28aaSamw 						break;
1238da6c28aaSamw 					}
1239da6c28aaSamw 				} else {
1240da6c28aaSamw 					n_zeroes = 0;
1241da6c28aaSamw 				}
1242da6c28aaSamw 			}
1243f96bd5c8SAlan Wright 			if (ix >= NDR_STRING_MAX) {
1244da6c28aaSamw 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1245da6c28aaSamw 				return (0);
1246da6c28aaSamw 			}
1247da6c28aaSamw 			size_is = ix+1;
1248da6c28aaSamw 		}
1249da6c28aaSamw 
1250da6c28aaSamw 		first_is = 0;
125155bf511dSas 
12528d7e4166Sjose borrego 		if (nds->flags & NDS_F_NOTERM)
125355bf511dSas 			length_is = size_is - 1;
125455bf511dSas 		else
125555bf511dSas 			length_is = size_is;
1256da6c28aaSamw 
12578d7e4166Sjose borrego 		if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
12588d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
12598d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
1260da6c28aaSamw 			return (0);		/* error already set */
1261da6c28aaSamw 		break;
1262da6c28aaSamw 
1263da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
12648d7e4166Sjose borrego 		if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
12658d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
12668d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
1267da6c28aaSamw 			return (0);		/* error already set */
1268da6c28aaSamw 
1269da6c28aaSamw 		/*
1270*1ca4e8dfSGordon Ross 		 * Enforce bounds on: size_is, first_is, length_is
1271*1ca4e8dfSGordon Ross 		 *
1272da6c28aaSamw 		 * In addition to the first_is check, we used to check that
1273da6c28aaSamw 		 * size_is or size_is-1 was equal to length_is but Windows95
1274da6c28aaSamw 		 * doesn't conform to this "rule" (see variable part below).
1275da6c28aaSamw 		 * The srvmgr tool for Windows95 sent the following values
1276da6c28aaSamw 		 * for a path string:
1277da6c28aaSamw 		 *
1278da6c28aaSamw 		 *	size_is   = 261 (0x105)
1279da6c28aaSamw 		 *	first_is  = 0
1280da6c28aaSamw 		 *	length_is = 53  (0x35)
1281da6c28aaSamw 		 *
1282da6c28aaSamw 		 * The length_is was correct (for the given path) but the
1283da6c28aaSamw 		 * size_is was the maximum path length rather than being
1284da6c28aaSamw 		 * related to length_is.
1285da6c28aaSamw 		 */
1286*1ca4e8dfSGordon Ross 		if (size_is > NDR_STRING_MAX) {
1287*1ca4e8dfSGordon Ross 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1288*1ca4e8dfSGordon Ross 			return (0);
1289*1ca4e8dfSGordon Ross 		}
1290da6c28aaSamw 		if (first_is != 0) {
1291da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1292da6c28aaSamw 			return (0);
1293da6c28aaSamw 		}
1294*1ca4e8dfSGordon Ross 		if (length_is > size_is) {
1295*1ca4e8dfSGordon Ross 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1296*1ca4e8dfSGordon Ross 			return (0);
1297*1ca4e8dfSGordon Ross 		}
1298da6c28aaSamw 
1299da6c28aaSamw 		if (ti == &ndt_s_wchar) {
1300da6c28aaSamw 			/*
1301da6c28aaSamw 			 * Decoding Unicode to UTF-8; we need to allow
1302da6c28aaSamw 			 * for the maximum possible char size. It would
1303da6c28aaSamw 			 * be nice to use mbequiv_strlen but the string
1304da6c28aaSamw 			 * may not be null terminated.
1305da6c28aaSamw 			 */
13063299f39fSGordon Ross 			n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
1307da6c28aaSamw 		} else {
1308da6c28aaSamw 			n_alloc = (size_is + 1) * is_varlen;
1309da6c28aaSamw 		}
1310da6c28aaSamw 
13118d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1312da6c28aaSamw 		if (!valp) {
1313da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1314da6c28aaSamw 			return (0);
1315da6c28aaSamw 		}
1316da6c28aaSamw 
1317da6c28aaSamw 		bzero(valp, (size_is+1) * is_varlen);
1318da6c28aaSamw 
1319da6c28aaSamw 		if (outer_ref->backptr)
1320da6c28aaSamw 			*outer_ref->backptr = valp;
1321da6c28aaSamw 		outer_ref->datum = valp;
1322da6c28aaSamw 		break;
1323da6c28aaSamw 
1324da6c28aaSamw 	default:
1325da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1326da6c28aaSamw 		return (0);
1327da6c28aaSamw 	}
1328da6c28aaSamw 
1329da6c28aaSamw 	/*
1330da6c28aaSamw 	 * Variable part - exactly length_is of these.
1331da6c28aaSamw 	 *
1332da6c28aaSamw 	 * Usually, length_is is same as size_is and includes nul.
1333da6c28aaSamw 	 * Some protocols use length_is = size_is-1, and length_is does
1334da6c28aaSamw 	 * not include the nul (which is more consistent with DCE spec).
1335da6c28aaSamw 	 * If the length_is is 0, there is no data following the
1336da6c28aaSamw 	 * sizing header, regardless of size_is.
1337da6c28aaSamw 	 */
1338da6c28aaSamw 	n_variable = length_is * is_varlen;
1339da6c28aaSamw 
1340da6c28aaSamw 	/* sum them up to determine the PDU space required */
1341da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
1342da6c28aaSamw 
1343da6c28aaSamw 	/* similar sum to determine how much local memory is required */
1344da6c28aaSamw 	n_alloc = n_fixed + n_variable;
1345da6c28aaSamw 
13468d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1347da6c28aaSamw 	if (!rc)
1348da6c28aaSamw 		return (rc);		/* error already set */
1349da6c28aaSamw 
1350da6c28aaSamw 	if (length_is > 0) {
1351da6c28aaSamw 		bzero(&myref, sizeof (myref));
13528d7e4166Sjose borrego 		myref.stream = nds;
1353da6c28aaSamw 		myref.enclosing = outer_ref;
1354da6c28aaSamw 		myref.ti = outer_ref->ti;
1355da6c28aaSamw 		myref.datum = outer_ref->datum;
1356da6c28aaSamw 		myref.name = "OUTER-STRING";
1357da6c28aaSamw 		myref.outer_flags = NDR_F_IS_STRING;
1358da6c28aaSamw 		myref.inner_flags = NDR_F_NONE;
1359da6c28aaSamw 
1360da6c28aaSamw 		/*
13618d7e4166Sjose borrego 		 * Set up size_is and strlen_is for ndr_s_wchar.
1362da6c28aaSamw 		 */
1363dc20a302Sas 		myref.size_is = size_is;
1364da6c28aaSamw 		myref.strlen_is = length_is;
1365da6c28aaSamw 	}
1366da6c28aaSamw 
1367da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset + 12;
1368da6c28aaSamw 
1369da6c28aaSamw 	/*
1370da6c28aaSamw 	 * Don't try to decode empty strings.
1371da6c28aaSamw 	 */
1372da6c28aaSamw 	if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
13738d7e4166Sjose borrego 		nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1374da6c28aaSamw 		return (1);
1375da6c28aaSamw 	}
1376da6c28aaSamw 
1377da6c28aaSamw 	if ((size_is != 0) && (length_is != 0)) {
13788d7e4166Sjose borrego 		rc = ndr_inner(&myref);
1379da6c28aaSamw 		if (!rc)
1380da6c28aaSamw 			return (rc);		/* error already set */
1381da6c28aaSamw 	}
1382da6c28aaSamw 
13838d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1384da6c28aaSamw 	return (1);
1385da6c28aaSamw }
1386da6c28aaSamw 
1387da6c28aaSamw int
13888d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
1389da6c28aaSamw     unsigned long *sizing_p)
1390da6c28aaSamw {
1391*1ca4e8dfSGordon Ross 	ndr_stream_t	*nds = outer_ref->stream;
13928d7e4166Sjose borrego 	unsigned long	pdu_offset;
13938d7e4166Sjose borrego 	int		rc;
1394da6c28aaSamw 
1395da6c28aaSamw 	pdu_offset = outer_ref->pdu_offset + offset;
1396da6c28aaSamw 
13978d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
13988d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
13998d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1400da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1401da6c28aaSamw 		return (0);
1402da6c28aaSamw 	}
1403da6c28aaSamw 
14048d7e4166Sjose borrego 	switch (nds->m_op) {
1405da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1406da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1407da6c28aaSamw 		return (0);
1408da6c28aaSamw 
1409da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
14108d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14118d7e4166Sjose borrego 		    nds->swap, outer_ref);
1412da6c28aaSamw 		break;
1413da6c28aaSamw 
1414da6c28aaSamw 	default:
1415da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1416da6c28aaSamw 		return (0);
1417da6c28aaSamw 	}
1418da6c28aaSamw 
1419da6c28aaSamw 	return (rc);
1420da6c28aaSamw }
1421da6c28aaSamw 
1422da6c28aaSamw int
14238d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
1424da6c28aaSamw     unsigned long *sizing_p)
1425da6c28aaSamw {
1426*1ca4e8dfSGordon Ross 	ndr_stream_t	*nds = outer_ref->stream;
14278d7e4166Sjose borrego 	unsigned long	pdu_offset;
14288d7e4166Sjose borrego 	int		rc;
1429da6c28aaSamw 
1430da6c28aaSamw 	pdu_offset = outer_ref->pdu_offset + offset;
1431da6c28aaSamw 
14328d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
14338d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
14348d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1435da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1436da6c28aaSamw 		return (0);
1437da6c28aaSamw 	}
1438da6c28aaSamw 
14398d7e4166Sjose borrego 	switch (nds->m_op) {
1440da6c28aaSamw 	case NDR_M_OP_MARSHALL:
14418d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14428d7e4166Sjose borrego 		    nds->swap, outer_ref);
1443da6c28aaSamw 		break;
1444da6c28aaSamw 
1445da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1446da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1447da6c28aaSamw 		return (0);
1448da6c28aaSamw 
1449da6c28aaSamw 	default:
1450da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1451da6c28aaSamw 		return (0);
1452da6c28aaSamw 	}
1453da6c28aaSamw 
1454da6c28aaSamw 	return (rc);
1455da6c28aaSamw }
1456da6c28aaSamw 
1457da6c28aaSamw /*
1458da6c28aaSamw  * All OUTER constructs begin on a mod4 (dword) boundary - except
1459da6c28aaSamw  * for the ones that don't: some MSRPC calls appear to use word or
1460da6c28aaSamw  * packed alignment.  Strings appear to be dword aligned.
1461da6c28aaSamw  */
1462da6c28aaSamw int
14638d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref)
1464da6c28aaSamw {
1465*1ca4e8dfSGordon Ross 	ndr_stream_t	*nds = outer_ref->stream;
14668d7e4166Sjose borrego 	int		rc;
14678d7e4166Sjose borrego 	unsigned	n_pad;
14688d7e4166Sjose borrego 	unsigned	align;
1469da6c28aaSamw 
1470da6c28aaSamw 	if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1471da6c28aaSamw 		align = outer_ref->ti->alignment;
14728d7e4166Sjose borrego 		n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
1473da6c28aaSamw 	} else {
14748d7e4166Sjose borrego 		n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
1475da6c28aaSamw 	}
1476da6c28aaSamw 
1477da6c28aaSamw 	if (n_pad == 0)
1478da6c28aaSamw 		return (1);	/* already aligned, often the case */
1479da6c28aaSamw 
14808d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_pad))
1481da6c28aaSamw 		return (0);	/* error already set */
1482da6c28aaSamw 
14838d7e4166Sjose borrego 	switch (nds->m_op) {
1484da6c28aaSamw 	case NDR_M_OP_MARSHALL:
14858d7e4166Sjose borrego 		rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
1486da6c28aaSamw 		if (!rc) {
1487da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1488da6c28aaSamw 			return (0);
1489da6c28aaSamw 		}
1490da6c28aaSamw 		break;
1491da6c28aaSamw 
1492da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1493da6c28aaSamw 		break;
1494da6c28aaSamw 
1495da6c28aaSamw 	default:
1496da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1497da6c28aaSamw 		return (0);
1498da6c28aaSamw 	}
1499da6c28aaSamw 
15008d7e4166Sjose borrego 	nds->pdu_scan_offset += n_pad;
1501da6c28aaSamw 	return (1);
1502da6c28aaSamw }
1503da6c28aaSamw 
1504da6c28aaSamw int
15058d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
1506da6c28aaSamw {
1507*1ca4e8dfSGordon Ross 	ndr_stream_t	*nds = outer_ref->stream;
15088d7e4166Sjose borrego 	unsigned long	pdu_want_size;
15098d7e4166Sjose borrego 	int		rc, is_ok = 0;
1510da6c28aaSamw 
15118d7e4166Sjose borrego 	pdu_want_size = nds->pdu_scan_offset + n_total;
1512da6c28aaSamw 
15138d7e4166Sjose borrego 	if (pdu_want_size <= nds->pdu_max_size) {
1514da6c28aaSamw 		is_ok = 1;
1515da6c28aaSamw 	}
1516da6c28aaSamw 
15178d7e4166Sjose borrego 	switch (nds->m_op) {
1518da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1519da6c28aaSamw 		if (is_ok)
1520da6c28aaSamw 			break;
15218d7e4166Sjose borrego 		rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
1522da6c28aaSamw 		if (!rc) {
1523da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1524da6c28aaSamw 			return (0);
1525da6c28aaSamw 		}
1526da6c28aaSamw 		break;
1527da6c28aaSamw 
1528da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1529da6c28aaSamw 		if (is_ok)
1530da6c28aaSamw 			break;
1531da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1532da6c28aaSamw 		return (0);
1533da6c28aaSamw 
1534da6c28aaSamw 	default:
1535da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1536da6c28aaSamw 		return (0);
1537da6c28aaSamw 	}
1538da6c28aaSamw 
15398d7e4166Sjose borrego 	if (nds->pdu_size < pdu_want_size)
15408d7e4166Sjose borrego 		nds->pdu_size = pdu_want_size;
1541da6c28aaSamw 
1542da6c28aaSamw 	outer_ref->pdu_end_offset = pdu_want_size;
1543da6c28aaSamw 	return (1);
1544da6c28aaSamw }
1545da6c28aaSamw 
1546da6c28aaSamw /*
1547da6c28aaSamw  * INNER ELEMENTS
1548da6c28aaSamw  *
1549da6c28aaSamw  * The local datum (arg_ref->datum) already exists, there is no need to
1550da6c28aaSamw  * malloc() it.  The datum should point at a member of a structure.
1551da6c28aaSamw  *
15528d7e4166Sjose borrego  * For the most part, ndr_inner() and its helpers are just a sanity
1553da6c28aaSamw  * check.  The underlying ti->ndr_func() could be called immediately
1554da6c28aaSamw  * for non-pointer elements.  For the sake of robustness, we detect
1555da6c28aaSamw  * run-time errors here.  Most of the situations this protects against
1556da6c28aaSamw  * have already been checked by the IDL compiler.  This is also a
1557da6c28aaSamw  * common point for processing of all data, and so is a convenient
1558da6c28aaSamw  * place to work from for debugging.
1559da6c28aaSamw  */
1560da6c28aaSamw int
15618d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref)
1562da6c28aaSamw {
1563*1ca4e8dfSGordon Ross 	ndr_typeinfo_t	*ti = arg_ref->ti;
1564da6c28aaSamw 	int	is_varlen = ti->pdu_size_variable_part;
1565da6c28aaSamw 	int	is_union = NDR_IS_UNION(ti);
1566da6c28aaSamw 	int	error = NDR_ERR_INNER_PARAMS_BAD;
1567da6c28aaSamw 	int	params;
1568da6c28aaSamw 
1569da6c28aaSamw 	params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1570da6c28aaSamw 
1571da6c28aaSamw 	switch (params) {
1572da6c28aaSamw 	case NDR_F_NONE:
1573da6c28aaSamw 		if (is_union) {
1574da6c28aaSamw 			error = NDR_ERR_SWITCH_VALUE_MISSING;
1575da6c28aaSamw 			break;
1576da6c28aaSamw 		}
1577da6c28aaSamw 		return (*ti->ndr_func)(arg_ref);
1578da6c28aaSamw 
1579da6c28aaSamw 	case NDR_F_SIZE_IS:
1580da6c28aaSamw 	case NDR_F_DIMENSION_IS:
1581da6c28aaSamw 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:   /* pointer to something */
1582da6c28aaSamw 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1583da6c28aaSamw 		if (is_varlen) {
1584da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1585da6c28aaSamw 			break;
1586da6c28aaSamw 		}
1587da6c28aaSamw 		if (is_union) {
1588da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1589da6c28aaSamw 			break;
1590da6c28aaSamw 		}
1591da6c28aaSamw 		if (params & NDR_F_IS_POINTER)
15928d7e4166Sjose borrego 			return (ndr_inner_pointer(arg_ref));
1593da6c28aaSamw 		else if (params & NDR_F_IS_REFERENCE)
15948d7e4166Sjose borrego 			return (ndr_inner_reference(arg_ref));
1595da6c28aaSamw 		else
15968d7e4166Sjose borrego 			return (ndr_inner_array(arg_ref));
1597da6c28aaSamw 
1598da6c28aaSamw 	case NDR_F_IS_POINTER:	/* type is pointer to one something */
1599da6c28aaSamw 		if (is_union) {
1600da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1601da6c28aaSamw 			break;
1602da6c28aaSamw 		}
16038d7e4166Sjose borrego 		return (ndr_inner_pointer(arg_ref));
1604da6c28aaSamw 
1605da6c28aaSamw 	case NDR_F_IS_REFERENCE:	/* type is pointer to one something */
1606da6c28aaSamw 		if (is_union) {
1607da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1608da6c28aaSamw 			break;
1609da6c28aaSamw 		}
16108d7e4166Sjose borrego 		return (ndr_inner_reference(arg_ref));
1611da6c28aaSamw 
1612da6c28aaSamw 	case NDR_F_SWITCH_IS:
1613da6c28aaSamw 		if (!is_union) {
1614da6c28aaSamw 			error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1615da6c28aaSamw 			break;
1616da6c28aaSamw 		}
1617da6c28aaSamw 		return (*ti->ndr_func)(arg_ref);
1618da6c28aaSamw 
1619da6c28aaSamw 	default:
1620da6c28aaSamw 		error = NDR_ERR_INNER_PARAMS_BAD;
1621da6c28aaSamw 		break;
1622da6c28aaSamw 	}
1623da6c28aaSamw 
1624da6c28aaSamw 	/*
1625da6c28aaSamw 	 * If we get here, something is wrong. Most likely,
1626da6c28aaSamw 	 * the params flags do not match
1627da6c28aaSamw 	 */
1628da6c28aaSamw 	NDR_SET_ERROR(arg_ref, error);
1629da6c28aaSamw 	return (0);
1630da6c28aaSamw }
1631da6c28aaSamw 
1632da6c28aaSamw int
16338d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref)
1634da6c28aaSamw {
16358d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1636da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1637*1ca4e8dfSGordon Ross 	char		**valpp = (char **)arg_ref->datum;
1638*1ca4e8dfSGordon Ross 	ndr_ref_t	*outer_ref;
1639da6c28aaSamw 
16408d7e4166Sjose borrego 	if (!ndr__ulong(arg_ref))
1641da6c28aaSamw 		return (0);	/* error */
1642da6c28aaSamw 	if (!*valpp)
1643da6c28aaSamw 		return (1);	/* NULL pointer */
1644da6c28aaSamw 
16458d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1646da6c28aaSamw 	if (!outer_ref)
1647da6c28aaSamw 		return (0);	/* error already set */
1648da6c28aaSamw 
1649f96bd5c8SAlan Wright 	/*
1650f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1651f96bd5c8SAlan Wright 	 * Retain pointer flag for conformant arrays.
1652f96bd5c8SAlan Wright 	 */
1653da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1654f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1655f96bd5c8SAlan Wright 		outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1656f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET
1657da6c28aaSamw 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1658da6c28aaSamw 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1659da6c28aaSamw 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1660da6c28aaSamw 	}
1661f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */
1662da6c28aaSamw 
1663da6c28aaSamw 	outer_ref->backptr = valpp;
1664da6c28aaSamw 
16658d7e4166Sjose borrego 	switch (nds->m_op) {
1666da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1667da6c28aaSamw 		outer_ref->datum = *valpp;
1668da6c28aaSamw 		break;
1669da6c28aaSamw 
1670da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1671da6c28aaSamw 		/*
1672da6c28aaSamw 		 * This is probably wrong if the application allocated
1673da6c28aaSamw 		 * memory in advance.  Indicate no value for now.
1674da6c28aaSamw 		 * ONC RPC handles this case.
1675da6c28aaSamw 		 */
1676da6c28aaSamw 		*valpp = 0;
1677da6c28aaSamw 		outer_ref->datum = 0;
1678da6c28aaSamw 		break;
1679da6c28aaSamw 	}
1680da6c28aaSamw 
1681da6c28aaSamw 	return (1);		/* pointer dereference scheduled */
1682da6c28aaSamw }
1683da6c28aaSamw 
1684da6c28aaSamw int
16858d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref)
1686da6c28aaSamw {
16878d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1688da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
16898d7e4166Sjose borrego 	char		**valpp = (char **)arg_ref->datum;
16908d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
1691da6c28aaSamw 
16928d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1693da6c28aaSamw 	if (!outer_ref)
1694da6c28aaSamw 		return (0);	/* error already set */
1695da6c28aaSamw 
1696f96bd5c8SAlan Wright 	/*
1697f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1698f96bd5c8SAlan Wright 	 * Retain reference flag for conformant arrays.
1699f96bd5c8SAlan Wright 	 */
1700da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1701f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1702f96bd5c8SAlan Wright 		outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1703da6c28aaSamw #ifdef NDR_INNER_REF_NOT_YET
1704da6c28aaSamw 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1705da6c28aaSamw 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1706da6c28aaSamw 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1707da6c28aaSamw 	}
1708da6c28aaSamw #endif /* NDR_INNER_REF_NOT_YET */
1709da6c28aaSamw 
1710da6c28aaSamw 	outer_ref->backptr = valpp;
1711da6c28aaSamw 
17128d7e4166Sjose borrego 	switch (nds->m_op) {
1713da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1714da6c28aaSamw 		outer_ref->datum = *valpp;
1715da6c28aaSamw 		break;
1716da6c28aaSamw 
1717da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1718da6c28aaSamw 		/*
1719da6c28aaSamw 		 * This is probably wrong if the application allocated
1720da6c28aaSamw 		 * memory in advance.  Indicate no value for now.
1721da6c28aaSamw 		 * ONC RPC handles this case.
1722da6c28aaSamw 		 */
1723da6c28aaSamw 		*valpp = 0;
1724da6c28aaSamw 		outer_ref->datum = 0;
1725da6c28aaSamw 		break;
1726da6c28aaSamw 	}
1727da6c28aaSamw 
1728da6c28aaSamw 	return (1);		/* pointer dereference scheduled */
1729da6c28aaSamw }
1730da6c28aaSamw 
1731da6c28aaSamw int
17328d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref)
1733da6c28aaSamw {
17348d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = encl_ref->ti;
17358d7e4166Sjose borrego 	ndr_ref_t		myref;
1736da6c28aaSamw 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1737da6c28aaSamw 	unsigned long		n_elem;
1738da6c28aaSamw 	unsigned long		i;
1739da6c28aaSamw 	char			name[30];
1740da6c28aaSamw 
1741da6c28aaSamw 	if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1742da6c28aaSamw 		/* now is the time to check/set size */
17438d7e4166Sjose borrego 		if (!ndr_size_is(encl_ref))
1744da6c28aaSamw 			return (0);	/* error already set */
1745da6c28aaSamw 		n_elem = encl_ref->size_is;
1746da6c28aaSamw 	} else {
1747da6c28aaSamw 		assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1748da6c28aaSamw 		n_elem = encl_ref->dimension_is;
1749da6c28aaSamw 	}
1750da6c28aaSamw 
1751da6c28aaSamw 	bzero(&myref, sizeof (myref));
1752da6c28aaSamw 	myref.enclosing = encl_ref;
1753da6c28aaSamw 	myref.stream = encl_ref->stream;
1754da6c28aaSamw 	myref.packed_alignment = 0;
1755da6c28aaSamw 	myref.ti = ti;
1756da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1757da6c28aaSamw 
1758da6c28aaSamw 	for (i = 0; i < n_elem; i++) {
17593299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
1760da6c28aaSamw 		myref.name = name;
1761da6c28aaSamw 		myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1762da6c28aaSamw 		myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1763da6c28aaSamw 
17648d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1765da6c28aaSamw 			return (0);
1766da6c28aaSamw 	}
1767da6c28aaSamw 
1768da6c28aaSamw 	return (1);
1769da6c28aaSamw }
1770da6c28aaSamw 
1771da6c28aaSamw 
1772da6c28aaSamw /*
1773da6c28aaSamw  * BASIC TYPES
1774da6c28aaSamw  */
1775da6c28aaSamw #define	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
17768d7e4166Sjose borrego     extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
17778d7e4166Sjose borrego     ndr_typeinfo_t ndt_##TYPE = { \
1778da6c28aaSamw 	1,		/* NDR version */ \
1779da6c28aaSamw 	(SIZE)-1,	/* alignment */ \
1780da6c28aaSamw 	NDR_F_NONE,	/* flags */ \
17818d7e4166Sjose borrego 	ndr_##TYPE,	/* ndr_func */ \
1782da6c28aaSamw 	SIZE,		/* pdu_size_fixed_part */ \
1783da6c28aaSamw 	0,		/* pdu_size_variable_part */ \
1784da6c28aaSamw 	SIZE,		/* c_size_fixed_part */ \
1785da6c28aaSamw 	0,		/* c_size_variable_part */ \
1786da6c28aaSamw 	}; \
17878d7e4166Sjose borrego     int ndr_##TYPE(struct ndr_reference *ref) { \
17888d7e4166Sjose borrego 	return (ndr_basic_integer(ref, SIZE)); \
1789da6c28aaSamw }
1790da6c28aaSamw 
1791da6c28aaSamw #define	MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
17928d7e4166Sjose borrego     extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
17938d7e4166Sjose borrego     ndr_typeinfo_t ndt_s##TYPE = { \
1794da6c28aaSamw 	1,		/* NDR version */ \
1795da6c28aaSamw 	(SIZE)-1,	/* alignment */ \
1796da6c28aaSamw 	NDR_F_STRING,	/* flags */ \
17978d7e4166Sjose borrego 	ndr_s##TYPE,	/* ndr_func */ \
1798da6c28aaSamw 	0,		/* pdu_size_fixed_part */ \
1799da6c28aaSamw 	SIZE,		/* pdu_size_variable_part */ \
1800da6c28aaSamw 	0,		/* c_size_fixed_part */ \
1801da6c28aaSamw 	SIZE,		/* c_size_variable_part */ \
1802da6c28aaSamw 	}; \
18038d7e4166Sjose borrego     int ndr_s##TYPE(struct ndr_reference *ref) { \
18048d7e4166Sjose borrego 	return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
1805da6c28aaSamw }
1806da6c28aaSamw 
1807da6c28aaSamw #define	MAKE_BASIC_TYPE(TYPE, SIZE) \
1808da6c28aaSamw 	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1809da6c28aaSamw 	MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1810da6c28aaSamw 
18118d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned);
18128d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
1813da6c28aaSamw 
1814*1ca4e8dfSGordon Ross /* BEGIN CSTYLED */
18153299f39fSGordon Ross /* Comments to be nice to those searching for these types. */
18163299f39fSGordon Ross MAKE_BASIC_TYPE(_char, 1)	/* ndt__char,  ndt_s_char */
18173299f39fSGordon Ross MAKE_BASIC_TYPE(_uchar, 1)	/* ndt__uchar, ndt_s_uchar */
18183299f39fSGordon Ross MAKE_BASIC_TYPE(_short, 2)	/* ndt__short, ndt_s_short */
18193299f39fSGordon Ross MAKE_BASIC_TYPE(_ushort, 2)	/* ndt__ushort, ndt_s_ushort */
18203299f39fSGordon Ross MAKE_BASIC_TYPE(_long, 4)	/* ndt__long,  ndt_s_long */
18213299f39fSGordon Ross MAKE_BASIC_TYPE(_ulong, 4)	/* ndt__ulong, ndt_s_ulong */
1822da6c28aaSamw 
18233299f39fSGordon Ross MAKE_BASIC_TYPE_BASE(_wchar, 2)	/* ndt__wchar, ndt_s_wchar */
1824*1ca4e8dfSGordon Ross /* END CSTYLED */
1825da6c28aaSamw 
1826da6c28aaSamw int
18278d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size)
1828da6c28aaSamw {
18293299f39fSGordon Ross 	ndr_stream_t	*nds = ref->stream;
1830*1ca4e8dfSGordon Ross 	char		*valp = (char *)ref->datum;
18318d7e4166Sjose borrego 	int		rc;
1832da6c28aaSamw 
18338d7e4166Sjose borrego 	switch (nds->m_op) {
1834da6c28aaSamw 	case NDR_M_OP_MARSHALL:
18358d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
18368d7e4166Sjose borrego 		    valp, nds->swap, ref);
1837da6c28aaSamw 		break;
1838da6c28aaSamw 
1839da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
18408d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
18418d7e4166Sjose borrego 		    valp, nds->swap, ref);
1842da6c28aaSamw 		break;
1843da6c28aaSamw 
1844da6c28aaSamw 	default:
1845da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1846da6c28aaSamw 		return (0);
1847da6c28aaSamw 	}
1848da6c28aaSamw 
1849da6c28aaSamw 	return (rc);
1850da6c28aaSamw }
1851da6c28aaSamw 
1852da6c28aaSamw int
18538d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
1854da6c28aaSamw {
1855da6c28aaSamw 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1856da6c28aaSamw 	unsigned		size = type_under->pdu_size_fixed_part;
1857da6c28aaSamw 	char			*valp;
18588d7e4166Sjose borrego 	ndr_ref_t		myref;
1859da6c28aaSamw 	unsigned long		i;
1860da6c28aaSamw 	long			sense = 0;
1861da6c28aaSamw 	char			name[30];
1862da6c28aaSamw 
1863da6c28aaSamw 	assert(size != 0);
1864da6c28aaSamw 
1865da6c28aaSamw 	bzero(&myref, sizeof (myref));
1866da6c28aaSamw 	myref.enclosing = encl_ref;
1867da6c28aaSamw 	myref.stream = encl_ref->stream;
1868da6c28aaSamw 	myref.packed_alignment = 0;
1869da6c28aaSamw 	myref.ti = type_under;
1870da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1871da6c28aaSamw 	myref.name = name;
1872da6c28aaSamw 
1873da6c28aaSamw 	for (i = 0; i < NDR_STRING_MAX; i++) {
18743299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
1875da6c28aaSamw 		myref.pdu_offset = pdu_offset + i * size;
1876da6c28aaSamw 		valp = encl_ref->datum + i * size;
1877da6c28aaSamw 		myref.datum = valp;
1878da6c28aaSamw 
18798d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1880da6c28aaSamw 			return (0);
1881da6c28aaSamw 
1882da6c28aaSamw 		switch (size) {
1883da6c28aaSamw 		case 1:		sense = *valp; break;
1884da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1885da6c28aaSamw 		case 2:		sense = *(short *)valp; break;
1886da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1887da6c28aaSamw 		case 4:		sense = *(long *)valp; break;
1888da6c28aaSamw 		}
1889da6c28aaSamw 
1890da6c28aaSamw 		if (!sense)
1891da6c28aaSamw 			break;
1892da6c28aaSamw 	}
1893da6c28aaSamw 
1894da6c28aaSamw 	return (1);
1895da6c28aaSamw }
1896da6c28aaSamw 
1897da6c28aaSamw 
18988d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref);
18998d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = {
1900da6c28aaSamw 	1,		/* NDR version */
1901da6c28aaSamw 	2-1,		/* alignment */
1902da6c28aaSamw 	NDR_F_STRING,	/* flags */
19038d7e4166Sjose borrego 	ndr_s_wchar,	/* ndr_func */
1904da6c28aaSamw 	0,		/* pdu_size_fixed_part */
1905da6c28aaSamw 	2,		/* pdu_size_variable_part */
1906da6c28aaSamw 	0,		/* c_size_fixed_part */
1907da6c28aaSamw 	1,		/* c_size_variable_part */
1908da6c28aaSamw };
1909da6c28aaSamw 
1910da6c28aaSamw 
1911da6c28aaSamw /*
1912da6c28aaSamw  * Hand coded wchar function because all strings are transported
1913da6c28aaSamw  * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1914da6c28aaSamw  * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1915da6c28aaSamw  * convert from wide characters to multi-byte.
1916da6c28aaSamw  *
19173299f39fSGordon Ross  * The most critical thing to get right in this function is to
19183299f39fSGordon Ross  * marshall or unmarshall _exactly_ the number of elements the
19193299f39fSGordon Ross  * OtW length specifies, as saved by the caller in: strlen_is.
19203299f39fSGordon Ross  * Doing otherwise would leave us positioned at the wrong place
19213299f39fSGordon Ross  * in the data stream for whatever follows this.  Note that the
19223299f39fSGordon Ross  * string data covered by strlen_is may or may not include any
19233299f39fSGordon Ross  * null termination, but the converted string provided by the
19243299f39fSGordon Ross  * caller or returned always has a null terminator.
1925da6c28aaSamw  */
1926da6c28aaSamw int
19278d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref)
1928da6c28aaSamw {
19298d7e4166Sjose borrego 	ndr_stream_t		*nds = encl_ref->stream;
19303299f39fSGordon Ross 	char			*valp = encl_ref->datum;
19318d7e4166Sjose borrego 	ndr_ref_t		myref;
1932da6c28aaSamw 	char			name[30];
19333299f39fSGordon Ross 	ndr_wchar_t		wcs[NDR_STRING_MAX+1];
19343299f39fSGordon Ross 	size_t			i, slen, wlen;
19353299f39fSGordon Ross 
19363299f39fSGordon Ross 	/* This is enforced in ndr_outer_string() */
19373299f39fSGordon Ross 	assert(encl_ref->strlen_is <= NDR_STRING_MAX);
1938da6c28aaSamw 
19398d7e4166Sjose borrego 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1940da6c28aaSamw 		/*
1941da6c28aaSamw 		 * To avoid problems with zero length strings
1942da6c28aaSamw 		 * we can just null terminate here and be done.
1943da6c28aaSamw 		 */
1944da6c28aaSamw 		if (encl_ref->strlen_is == 0) {
1945da6c28aaSamw 			encl_ref->datum[0] = '\0';
1946da6c28aaSamw 			return (1);
1947da6c28aaSamw 		}
1948da6c28aaSamw 	}
1949da6c28aaSamw 
19503299f39fSGordon Ross 	/*
19513299f39fSGordon Ross 	 * If we're marshalling, convert the given string
19523299f39fSGordon Ross 	 * from UTF-8 into a local UCS-2 string.
19533299f39fSGordon Ross 	 */
19543299f39fSGordon Ross 	if (nds->m_op == NDR_M_OP_MARSHALL) {
19553299f39fSGordon Ross 		wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
19563299f39fSGordon Ross 		if (wlen == (size_t)-1)
19573299f39fSGordon Ross 			return (0);
19583299f39fSGordon Ross 		/*
19593299f39fSGordon Ross 		 * Add a nulls to make strlen_is.
19603299f39fSGordon Ross 		 * (always zero or one of them)
19613299f39fSGordon Ross 		 * Then null terminate at wlen,
19623299f39fSGordon Ross 		 * just for debug convenience.
19633299f39fSGordon Ross 		 */
19643299f39fSGordon Ross 		while (wlen < encl_ref->strlen_is)
19653299f39fSGordon Ross 			wcs[wlen++] = 0;
19663299f39fSGordon Ross 		wcs[wlen] = 0;
19673299f39fSGordon Ross 	}
19683299f39fSGordon Ross 
19693299f39fSGordon Ross 	/*
19703299f39fSGordon Ross 	 * Copy wire data to or from the local wc string.
19713299f39fSGordon Ross 	 * Always exactly strlen_is elements.
19723299f39fSGordon Ross 	 */
1973da6c28aaSamw 	bzero(&myref, sizeof (myref));
1974da6c28aaSamw 	myref.enclosing = encl_ref;
1975da6c28aaSamw 	myref.stream = encl_ref->stream;
1976da6c28aaSamw 	myref.packed_alignment = 0;
1977da6c28aaSamw 	myref.ti = &ndt__wchar;
1978da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1979da6c28aaSamw 	myref.name = name;
1980da6c28aaSamw 	myref.pdu_offset = encl_ref->pdu_offset;
19813299f39fSGordon Ross 	myref.datum = (char *)wcs;
19823299f39fSGordon Ross 	wlen = encl_ref->strlen_is;
1983da6c28aaSamw 
19843299f39fSGordon Ross 	for (i = 0; i < wlen; i++) {
19853299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
19868d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1987da6c28aaSamw 			return (0);
19883299f39fSGordon Ross 		myref.pdu_offset += sizeof (ndr_wchar_t);
19893299f39fSGordon Ross 		myref.datum	 += sizeof (ndr_wchar_t);
19903299f39fSGordon Ross 	}
1991da6c28aaSamw 
19923299f39fSGordon Ross 	/*
19933299f39fSGordon Ross 	 * If this is unmarshall, convert the local UCS-2 string
19943299f39fSGordon Ross 	 * into a UTF-8 string in the caller's buffer.  The caller
19953299f39fSGordon Ross 	 * previously determined the space required and provides a
19963299f39fSGordon Ross 	 * buffer of sufficient size.
19973299f39fSGordon Ross 	 */
19983299f39fSGordon Ross 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
19993299f39fSGordon Ross 		wcs[wlen] = 0;
2000d1855c81SGordon Ross 		slen = encl_ref->size_is * NDR_MB_CHAR_MAX;
2001d1855c81SGordon Ross 		slen = ndr__wcstombs(valp, wcs, slen);
20023299f39fSGordon Ross 		if (slen == (size_t)-1)
20033299f39fSGordon Ross 			return (0);
20043299f39fSGordon Ross 		valp[slen] = '\0';
2005da6c28aaSamw 	}
2006da6c28aaSamw 
2007da6c28aaSamw 	return (1);
2008da6c28aaSamw }
200955bf511dSas 
201055bf511dSas /*
201155bf511dSas  * Converts a multibyte character string to a little-endian, wide-char
201255bf511dSas  * string.  No more than nwchars wide characters are stored.
201355bf511dSas  * A terminating null wide character is appended if there is room.
201455bf511dSas  *
201555bf511dSas  * Returns the number of wide characters converted, not counting
201655bf511dSas  * any terminating null wide character.  Returns -1 if an invalid
201755bf511dSas  * multibyte character is encountered.
201855bf511dSas  */
20193299f39fSGordon Ross /* ARGSUSED */
202055bf511dSas size_t
20213299f39fSGordon Ross ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
202255bf511dSas     size_t nwchars)
202355bf511dSas {
20243299f39fSGordon Ross 	size_t len;
202555bf511dSas 
202655bf511dSas #ifdef _BIG_ENDIAN
20273299f39fSGordon Ross 	if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
20283299f39fSGordon Ross 		/* Make WC string in LE order. */
20293299f39fSGordon Ross 		len = ndr__mbstowcs_le(wcs, mbs, nwchars);
20303299f39fSGordon Ross 	} else
203155bf511dSas #endif
20323299f39fSGordon Ross 		len = ndr__mbstowcs(wcs, mbs, nwchars);
203355bf511dSas 
20343299f39fSGordon Ross 	return (len);
203555bf511dSas }
2036