xref: /illumos-gate/usr/src/lib/libmlrpc/common/ndr_process.c (revision d1855c8182d5cf1cd290336767a7c8e7537c13a2)
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.
2433f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
25*d1855c81SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * Network Data Representation (NDR) is a compatible subset of the DCE RPC
30da6c28aaSamw  * and MSRPC NDR.  NDR is used to move parameters consisting of
31da6c28aaSamw  * complicated trees of data constructs between an RPC client and server.
32da6c28aaSamw  */
33da6c28aaSamw 
3455bf511dSas #include <sys/byteorder.h>
35da6c28aaSamw #include <strings.h>
36da6c28aaSamw #include <assert.h>
37da6c28aaSamw #include <string.h>
383299f39fSGordon Ross #include <stdio.h>
39da6c28aaSamw #include <stdlib.h>
40da6c28aaSamw 
413299f39fSGordon Ross #include <libmlrpc.h>
423299f39fSGordon Ross #include <ndr_wchar.h>
43da6c28aaSamw 
44da6c28aaSamw #define	NDR_IS_UNION(T)	\
45da6c28aaSamw 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
46da6c28aaSamw #define	NDR_IS_STRING(T)	\
47da6c28aaSamw 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
48da6c28aaSamw 
498d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar;
50da6c28aaSamw 
51da6c28aaSamw /*
52da6c28aaSamw  * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
53da6c28aaSamw  *
54da6c28aaSamw  * Each parameter (call arguments and return values) is a TOP-MOST item.
55da6c28aaSamw  * A TOP-MOST item consists of one or more OUTER items.  An OUTER item
56da6c28aaSamw  * consists of one or more INNER items.  There are important differences
57da6c28aaSamw  * between each kind, which, primarily, have to do with the allocation
58da6c28aaSamw  * of memory to contain data structures and the order of processing.
59da6c28aaSamw  *
60da6c28aaSamw  * This is most easily demonstrated with a short example.
61da6c28aaSamw  * Consider these structures:
62da6c28aaSamw  *
63da6c28aaSamw  *	struct top_param {
64da6c28aaSamw  *		long		level;
65da6c28aaSamw  *		struct list *	head;
66da6c28aaSamw  *		long		count;
67da6c28aaSamw  *	};
68da6c28aaSamw  *
69da6c28aaSamw  *	struct list {
70da6c28aaSamw  *		struct list *	next;
71da6c28aaSamw  *		char *		str; // a string
72da6c28aaSamw  *	};
73da6c28aaSamw  *
74da6c28aaSamw  * Now, consider an instance tree like this:
75da6c28aaSamw  *
76da6c28aaSamw  *	+---------+       +-------+       +-------+
77da6c28aaSamw  *	|top_param|  +--->|list #1|  +--->|list #2|
78da6c28aaSamw  *	+---------+  |    +-------+  |    +-------+
79da6c28aaSamw  *	| level   |  |    | next ----+    | next --->(NULL)
80da6c28aaSamw  *	| head   ----+    | str  -->"foo" | str  -->"bar"
81da6c28aaSamw  *	| count   |       | flag  |       | flag  |
82da6c28aaSamw  *	+---------+       +-------+       +-------+
83da6c28aaSamw  *
84da6c28aaSamw  * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
85da6c28aaSamw  * The vertical bars (|) indicate OUTER construct boundaries.
86da6c28aaSamw  *
87da6c28aaSamw  *   +-----+----------------------+----------------------+-----+-----+-----+
88da6c28aaSamw  *   |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
89da6c28aaSamw  *   +-----+----------------------+----------------------+-----+-----+-----+
90da6c28aaSamw  *   level |<----------------------- head -------------------------->|count
91da6c28aaSamw  *   TOP    TOP                                                       TOP
92da6c28aaSamw  *
93da6c28aaSamw  * Here's what to notice:
94da6c28aaSamw  *
95da6c28aaSamw  * - The members of the TOP-MOST construct are scattered through the Stub
96da6c28aaSamw  *   Data in the order they occur.  This example shows a TOP-MOST construct
97da6c28aaSamw  *   consisting of atomic types (pointers and integers).  A construct
98da6c28aaSamw  *   (struct) within the TOP-MOST construct would be contiguous and not
99da6c28aaSamw  *   scattered.
100da6c28aaSamw  *
101da6c28aaSamw  * - The members of OUTER constructs are contiguous, which allows for
102da6c28aaSamw  *   non-copied relocated (fixed-up) data structures at the packet's
103da6c28aaSamw  *   destination.  We don't do fix-ups here.  The pointers within the
104da6c28aaSamw  *   OUTER constructs are processed depth-first in the order that they
105da6c28aaSamw  *   occur.  If they were processed breadth first, the sequence would
106da6c28aaSamw  *   be #1,"foo",#2,"bar".  This is tricky because OUTER constructs may
107da6c28aaSamw  *   be variable length, and pointers are often encountered before the
108da6c28aaSamw  *   size(s) is known.
109da6c28aaSamw  *
110da6c28aaSamw  * - The INNER constructs are simply the members of an OUTER construct.
111da6c28aaSamw  *
112da6c28aaSamw  * For comparison, consider how ONC RPC would handle the same tree of
113da6c28aaSamw  * data.  ONC requires very little buffering, while DCE requires enough
114da6c28aaSamw  * buffer space for the entire message.  ONC does atom-by-atom depth-first
115da6c28aaSamw  * (de)serialization and copy, while DCE allows for constructs to be
116da6c28aaSamw  * "fixed-up" (relocated) in place at the destination.  The packet data
117da6c28aaSamw  * for the same tree processed by ONC RPC would look like this:
118da6c28aaSamw  *
119da6c28aaSamw  *   +---------------------------------------------------------------------+
120da6c28aaSamw  *   |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
121da6c28aaSamw  *   +---------------------------------------------------------------------+
122da6c28aaSamw  *   TOP    #1      #2      #2     bar   #2      #1     foo   #1      TOP
123da6c28aaSamw  *
124da6c28aaSamw  * More details about each TOP-MOST, OUTER, and INNER constructs appear
125da6c28aaSamw  * throughout this source file near where such constructs are processed.
126da6c28aaSamw  *
127da6c28aaSamw  * NDR_REFERENCE
128da6c28aaSamw  *
1298d7e4166Sjose borrego  * The primary object for NDR is the ndr_ref_t.
130da6c28aaSamw  *
1318d7e4166Sjose borrego  * An ndr reference indicates the local datum (i.e. native "C" data
132da6c28aaSamw  * format), and the element within the Stub Data (contained within the
1338d7e4166Sjose borrego  * RPC PDU (protocol data unit).  An ndr reference also indicates,
134da6c28aaSamw  * largely as a debugging aid, something about the type of the
135da6c28aaSamw  * element/datum, and the enclosing construct for the element. The
1368d7e4166Sjose borrego  * ndr reference's are typically allocated on the stack as locals,
1378d7e4166Sjose borrego  * and the chain of ndr-reference.enclosing references is in reverse
138da6c28aaSamw  * order of the call graph.
139da6c28aaSamw  *
1408d7e4166Sjose borrego  * The ndr-reference.datum is a pointer to the local memory that
1418d7e4166Sjose borrego  * contains/receives the value. The ndr-reference.pdu_offset indicates
142da6c28aaSamw  * where in the Stub Data the value is to be stored/retrieved.
143da6c28aaSamw  *
1448d7e4166Sjose borrego  * The ndr-reference also contains various parameters to the NDR
1458d7e4166Sjose borrego  * process, such as ndr-reference.size_is, which indicates the size
1468d7e4166Sjose borrego  * of variable length data, or ndr-reference.switch_is, which
147da6c28aaSamw  * indicates the arm of a union to use.
148da6c28aaSamw  *
149da6c28aaSamw  * QUEUE OF OUTER REFERENCES
150da6c28aaSamw  *
151da6c28aaSamw  * Some OUTER constructs are variable size.  Sometimes (often) we don't
152da6c28aaSamw  * know the size of the OUTER construct until after pointers have been
153da6c28aaSamw  * encountered. Hence, we can not begin processing the referent of the
154da6c28aaSamw  * pointer until after the referring OUTER construct is completely
155da6c28aaSamw  * processed, i.e. we don't know where to find/put the referent in the
156da6c28aaSamw  * Stub Data until we know the size of all its predecessors.
157da6c28aaSamw  *
158da6c28aaSamw  * This is managed using the queue of OUTER references.  The queue is
1598d7e4166Sjose borrego  * anchored in ndr_stream.outer_queue_head.  At any time,
1608d7e4166Sjose borrego  * ndr_stream.outer_queue_tailp indicates where to put the
1618d7e4166Sjose borrego  * ndr-reference for the next encountered pointer.
162da6c28aaSamw  *
163da6c28aaSamw  * Refer to the example above as we illustrate the queue here.  In these
164da6c28aaSamw  * illustrations, the queue entries are not the data structures themselves.
1658d7e4166Sjose borrego  * Rather, they are ndr-reference entries which **refer** to the data
166da6c28aaSamw  * structures in both the PDU and local memory.
167da6c28aaSamw  *
168da6c28aaSamw  * During some point in the processing, the queue looks like this:
169da6c28aaSamw  *
170da6c28aaSamw  *   outer_current -------v
171da6c28aaSamw  *   outer_queue_head --> list#1 --0
172da6c28aaSamw  *   outer_queue_tailp ---------&
173da6c28aaSamw  *
174da6c28aaSamw  * When the pointer #1.next is encountered, and entry is added to the
175da6c28aaSamw  * queue,
176da6c28aaSamw  *
177da6c28aaSamw  *   outer_current -------v
178da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --0
179da6c28aaSamw  *   outer_queue_tailp --------------------&
180da6c28aaSamw  *
181da6c28aaSamw  * and the members of #1 continue to be processed, which encounters
182da6c28aaSamw  * #1.str:
183da6c28aaSamw  *
184da6c28aaSamw  *   outer_current -------v
185da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
186da6c28aaSamw  *   outer_queue_tailp ------------------------------&
187da6c28aaSamw  *
1888d7e4166Sjose borrego  * Upon the completion of list#1, the processing continues by moving to
1898d7e4166Sjose borrego  * ndr_stream.outer_current->next, and the tail is set to this outer member:
190da6c28aaSamw  *
191da6c28aaSamw  *   outer_current ------------------v
192da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
193da6c28aaSamw  *   outer_queue_tailp --------------------&
194da6c28aaSamw  *
195da6c28aaSamw  * Space for list#2 is allocated, either in the Stub Data or of local
196da6c28aaSamw  * memory.  When #2.next is encountered, it is found to be the null
197da6c28aaSamw  * pointer and no reference is added to the queue.  When #2.str is
198da6c28aaSamw  * encountered, it is found to be valid, and a reference is added:
199da6c28aaSamw  *
200da6c28aaSamw  *   outer_current ------------------v
201da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
202da6c28aaSamw  *   outer_queue_tailp ------------------------------&
203da6c28aaSamw  *
204da6c28aaSamw  * Processing continues in a similar fashion with the string "bar",
205da6c28aaSamw  * which is variable-length.  At this point, memory for "bar" may be
206da6c28aaSamw  * malloc()ed during NDR_M_OP_UNMARSHALL:
207da6c28aaSamw  *
208da6c28aaSamw  *   outer_current -----------------------------v
209da6c28aaSamw  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
210da6c28aaSamw  *   outer_queue_tailp ------------------------------&
211da6c28aaSamw  *
212da6c28aaSamw  * And finishes on string "foo".  Notice that because "bar" is a
213da6c28aaSamw  * variable length string, and we don't know the PDU offset for "foo"
214da6c28aaSamw  * until we reach this point.
215da6c28aaSamw  *
216da6c28aaSamw  * When the queue is drained (current->next==0), processing continues
217da6c28aaSamw  * with the next TOP-MOST member.
218da6c28aaSamw  *
219da6c28aaSamw  * The queue of OUTER constructs manages the variable-length semantics
220da6c28aaSamw  * of OUTER constructs and satisfies the depth-first requirement.
221da6c28aaSamw  * We allow the queue to linger until the entire TOP-MOST structure is
222da6c28aaSamw  * processed as an aid to debugging.
223da6c28aaSamw  */
224da6c28aaSamw 
2258d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
2268d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *);
227da6c28aaSamw 
228da6c28aaSamw /*
229da6c28aaSamw  * TOP-MOST ELEMENTS
230da6c28aaSamw  *
231da6c28aaSamw  * This is fundamentally the first OUTER construct of the parameter,
232da6c28aaSamw  * possibly followed by more OUTER constructs due to pointers.  The
233da6c28aaSamw  * datum (local memory) for TOP-MOST constructs (structs) is allocated
234da6c28aaSamw  * by the caller of NDR.
235da6c28aaSamw  *
236da6c28aaSamw  * After the element is transferred, the outer_queue is drained.
237da6c28aaSamw  *
238da6c28aaSamw  * All we have to do is add an entry to the outer_queue for this
239da6c28aaSamw  * top-most member, and commence the outer_queue processing.
240da6c28aaSamw  */
241da6c28aaSamw int
2428d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
243da6c28aaSamw {
2448d7e4166Sjose borrego 	ndr_ref_t	myref;
245da6c28aaSamw 
246da6c28aaSamw 	bzero(&myref, sizeof (myref));
2478d7e4166Sjose borrego 	myref.stream = nds;
248da6c28aaSamw 	myref.datum = datum;
249da6c28aaSamw 	myref.name = "PROCESS";
250da6c28aaSamw 	myref.ti = ti;
251da6c28aaSamw 
2528d7e4166Sjose borrego 	return (ndr_topmost(&myref));
253da6c28aaSamw }
254da6c28aaSamw 
255da6c28aaSamw int
2568d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
257da6c28aaSamw {
2588d7e4166Sjose borrego 	ndr_ref_t	myref;
259da6c28aaSamw 
260da6c28aaSamw 	bzero(&myref, sizeof (myref));
2618d7e4166Sjose borrego 	myref.stream = nds;
262da6c28aaSamw 	myref.datum = datum;
263da6c28aaSamw 	myref.name = "OPERATION";
264da6c28aaSamw 	myref.ti = ti;
265da6c28aaSamw 	myref.inner_flags = NDR_F_SWITCH_IS;
266da6c28aaSamw 	myref.switch_is = opnum;
267da6c28aaSamw 
268da6c28aaSamw 	if (ti->type_flags != NDR_F_INTERFACE) {
269da6c28aaSamw 		NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
270da6c28aaSamw 		return (0);
271da6c28aaSamw 	}
272da6c28aaSamw 
273da6c28aaSamw 	return ((*ti->ndr_func)(&myref));
274da6c28aaSamw }
275da6c28aaSamw 
276da6c28aaSamw int
2778d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref)
278da6c28aaSamw {
2798d7e4166Sjose borrego 	ndr_typeinfo_t *ti = params_ref->ti;
280da6c28aaSamw 
281da6c28aaSamw 	if (ti->type_flags == NDR_F_OPERATION)
282da6c28aaSamw 		return (*ti->ndr_func) (params_ref);
283da6c28aaSamw 	else
2848d7e4166Sjose borrego 		return (ndr_topmost(params_ref));
285da6c28aaSamw }
286da6c28aaSamw 
287da6c28aaSamw int
2888d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref)
289da6c28aaSamw {
2908d7e4166Sjose borrego 	ndr_stream_t *nds;
2918d7e4166Sjose borrego 	ndr_typeinfo_t *ti;
2928d7e4166Sjose borrego 	ndr_ref_t *outer_ref = 0;
293da6c28aaSamw 	int	is_varlen;
294da6c28aaSamw 	int	is_string;
295da6c28aaSamw 	int	error;
296da6c28aaSamw 	int	rc;
297da6c28aaSamw 	unsigned n_fixed;
298da6c28aaSamw 	int	params;
299da6c28aaSamw 
300da6c28aaSamw 	assert(top_ref);
301da6c28aaSamw 	assert(top_ref->stream);
302da6c28aaSamw 	assert(top_ref->ti);
303da6c28aaSamw 
3048d7e4166Sjose borrego 	nds = top_ref->stream;
305da6c28aaSamw 	ti = top_ref->ti;
306da6c28aaSamw 
307da6c28aaSamw 	is_varlen = ti->pdu_size_variable_part;
308da6c28aaSamw 	is_string = NDR_IS_STRING(ti);
309da6c28aaSamw 
3108d7e4166Sjose borrego 	assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
3118d7e4166Sjose borrego 	assert(!nds->outer_current);
312da6c28aaSamw 
313da6c28aaSamw 	params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
314da6c28aaSamw 
315da6c28aaSamw 	switch (params) {
316da6c28aaSamw 	case NDR_F_NONE:
317da6c28aaSamw 	case NDR_F_SWITCH_IS:
318da6c28aaSamw 		if (is_string || is_varlen) {
319da6c28aaSamw 			error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
320da6c28aaSamw 			NDR_SET_ERROR(outer_ref, error);
321da6c28aaSamw 			return (0);
322da6c28aaSamw 		}
323da6c28aaSamw 		n_fixed = ti->pdu_size_fixed_part;
324da6c28aaSamw 		break;
325da6c28aaSamw 
326da6c28aaSamw 	case NDR_F_SIZE_IS:
327da6c28aaSamw 		error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
328da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
329da6c28aaSamw 		return (0);
330da6c28aaSamw 
331da6c28aaSamw 	case NDR_F_DIMENSION_IS:
332da6c28aaSamw 		if (is_varlen) {
333da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
334da6c28aaSamw 			NDR_SET_ERROR(outer_ref, error);
335da6c28aaSamw 			return (0);
336da6c28aaSamw 		}
337da6c28aaSamw 		n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
338da6c28aaSamw 		break;
339da6c28aaSamw 
340da6c28aaSamw 	case NDR_F_IS_POINTER:
341da6c28aaSamw 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
342da6c28aaSamw 		n_fixed = 4;
343da6c28aaSamw 		break;
344da6c28aaSamw 
345da6c28aaSamw 	case NDR_F_IS_REFERENCE:
346da6c28aaSamw 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
347da6c28aaSamw 		n_fixed = 0;
348da6c28aaSamw 		break;
349da6c28aaSamw 
350da6c28aaSamw 	default:
351da6c28aaSamw 		error = NDR_ERR_OUTER_PARAMS_BAD;
352da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
353da6c28aaSamw 		return (0);
354da6c28aaSamw 	}
355da6c28aaSamw 
3568d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(top_ref);
357da6c28aaSamw 	if (!outer_ref)
358da6c28aaSamw 		return (0);	/* error already set */
359da6c28aaSamw 
360da6c28aaSamw 	/*
361da6c28aaSamw 	 * Hand-craft the first OUTER construct and directly call
3628d7e4166Sjose borrego 	 * ndr_inner(). Then, run the outer_queue. We do this
3638d7e4166Sjose borrego 	 * because ndr_outer() wants to malloc() memory for
364da6c28aaSamw 	 * the construct, and we already have the memory.
365da6c28aaSamw 	 */
366da6c28aaSamw 
367da6c28aaSamw 	/* move the flags, etc, around again, undoes enter_outer_queue() */
368da6c28aaSamw 	outer_ref->inner_flags = top_ref->inner_flags;
369da6c28aaSamw 	outer_ref->outer_flags = 0;
370da6c28aaSamw 	outer_ref->datum = top_ref->datum;
371da6c28aaSamw 
372da6c28aaSamw 	/* All outer constructs start on a mod4 (longword) boundary */
3738d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
374da6c28aaSamw 		return (0);		/* error already set */
375da6c28aaSamw 
376da6c28aaSamw 	/* Regardless of what it is, this is where it starts */
3778d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
378da6c28aaSamw 
3798d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_fixed);
380da6c28aaSamw 	if (!rc)
381da6c28aaSamw 		return (0);		/* error already set */
382da6c28aaSamw 
383da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
384da6c28aaSamw 
385da6c28aaSamw 	/* set-up outer_current, as though run_outer_queue() was doing it */
3868d7e4166Sjose borrego 	nds->outer_current = outer_ref;
3878d7e4166Sjose borrego 	nds->outer_queue_tailp = &nds->outer_current->next;
3888d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
389da6c28aaSamw 
390da6c28aaSamw 	/* do the topmost member */
3918d7e4166Sjose borrego 	rc = ndr_inner(outer_ref);
392da6c28aaSamw 	if (!rc)
393da6c28aaSamw 		return (0);		/* error already set */
394da6c28aaSamw 
3958d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
396da6c28aaSamw 
397da6c28aaSamw 	/* advance, as though run_outer_queue() was doing it */
3988d7e4166Sjose borrego 	nds->outer_current = nds->outer_current->next;
3998d7e4166Sjose borrego 	return (ndr_run_outer_queue(nds));
400da6c28aaSamw }
401da6c28aaSamw 
4028d7e4166Sjose borrego static ndr_ref_t *
4038d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref)
404da6c28aaSamw {
4058d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
4068d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
407da6c28aaSamw 
408da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
4098d7e4166Sjose borrego 	outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
410da6c28aaSamw 	if (!outer_ref) {
411da6c28aaSamw 		NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
412da6c28aaSamw 		return (0);
413da6c28aaSamw 	}
414da6c28aaSamw 
415da6c28aaSamw 	*outer_ref = *arg_ref;
416da6c28aaSamw 
417da6c28aaSamw 	/* move advice in inner_flags to outer_flags */
418da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
419da6c28aaSamw 	outer_ref->inner_flags = 0;
4208d7e4166Sjose borrego 	outer_ref->enclosing = nds->outer_current;
421da6c28aaSamw 	outer_ref->backptr = 0;
422da6c28aaSamw 	outer_ref->datum = 0;
423da6c28aaSamw 
4248d7e4166Sjose borrego 	assert(nds->outer_queue_tailp);
425da6c28aaSamw 
4268d7e4166Sjose borrego 	outer_ref->next = *nds->outer_queue_tailp;
4278d7e4166Sjose borrego 	*nds->outer_queue_tailp = outer_ref;
4288d7e4166Sjose borrego 	nds->outer_queue_tailp = &outer_ref->next;
429da6c28aaSamw 	return (outer_ref);
430da6c28aaSamw }
431da6c28aaSamw 
432da6c28aaSamw int
4338d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds)
434da6c28aaSamw {
4358d7e4166Sjose borrego 	while (nds->outer_current) {
4368d7e4166Sjose borrego 		nds->outer_queue_tailp = &nds->outer_current->next;
437da6c28aaSamw 
4388d7e4166Sjose borrego 		if (!ndr_outer(nds->outer_current))
439da6c28aaSamw 			return (0);
440da6c28aaSamw 
4418d7e4166Sjose borrego 		nds->outer_current = nds->outer_current->next;
442da6c28aaSamw 	}
443da6c28aaSamw 
444da6c28aaSamw 	return (1);
445da6c28aaSamw }
446da6c28aaSamw 
447da6c28aaSamw /*
448da6c28aaSamw  * OUTER CONSTRUCTS
449da6c28aaSamw  *
450da6c28aaSamw  * OUTER constructs are where the real work is, which stems from the
451da6c28aaSamw  * variable-length potential.
452da6c28aaSamw  *
453da6c28aaSamw  * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
454da6c28aaSamw  *
455da6c28aaSamw  * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
456da6c28aaSamw  * VARYING, and VARYING/CONFORMANT.
457da6c28aaSamw  *
458da6c28aaSamw  * What makes this so tough is that the variable-length array may be well
459da6c28aaSamw  * encapsulated within the outer construct.  Further, because DCE(MS)/RPC
460da6c28aaSamw  * tries to keep the constructs contiguous in the data stream, the sizing
461da6c28aaSamw  * information precedes the entire OUTER construct.  The sizing information
462da6c28aaSamw  * must be used at the appropriate time, which can be after many, many,
463da6c28aaSamw  * many fixed-length elements.  During IDL type analysis, we know in
464da6c28aaSamw  * advance constructs that encapsulate variable-length constructs.  So,
465da6c28aaSamw  * we know when we have a sizing header and when we don't.  The actual
466da6c28aaSamw  * semantics of the header are largely deferred.
467da6c28aaSamw  *
468da6c28aaSamw  * Currently, VARYING constructs are not implemented but they are described
469da6c28aaSamw  * here in case they have to be implemented in the future.  Similarly,
470da6c28aaSamw  * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
471da6c28aaSamw  * not implemented.  Only one-dimensional, variable-length arrays are
472da6c28aaSamw  * supported.
473da6c28aaSamw  *
474da6c28aaSamw  * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
475da6c28aaSamw  *
476da6c28aaSamw  * All variable-length values are arrays.  These arrays may be embedded
477da6c28aaSamw  * well within another construct.  However, a variable-length construct
478da6c28aaSamw  * may ONLY appear as the last member of an enclosing construct.  Example:
479da6c28aaSamw  *
480da6c28aaSamw  *	struct credentials {
481da6c28aaSamw  *		ulong	uid, gid;
482da6c28aaSamw  *		ulong	n_gids;
483da6c28aaSamw  *	    [size_is(n_gids)]
484da6c28aaSamw  *		ulong	gids[*];    // variable-length.
485da6c28aaSamw  *	};
486da6c28aaSamw  *
487da6c28aaSamw  * CONFORMANT constructs have a dynamic size in local memory and in the
488da6c28aaSamw  * PDU.  The CONFORMANT quality is indicated by the [size_is()] advice.
489da6c28aaSamw  * CONFORMANT constructs have the following header:
490da6c28aaSamw  *
491da6c28aaSamw  *	struct conformant_header {
492da6c28aaSamw  *		ulong		size_is;
493da6c28aaSamw  *	};
494da6c28aaSamw  *
495da6c28aaSamw  * (Multi-dimensional CONFORMANT arrays have a similar header for each
496da6c28aaSamw  * dimension - not implemented).
497da6c28aaSamw  *
498da6c28aaSamw  * Example CONFORMANT construct:
499da6c28aaSamw  *
500da6c28aaSamw  *	struct user {
501da6c28aaSamw  *		char *			name;
502da6c28aaSamw  *		struct credentials	cred;	// see above
503da6c28aaSamw  *	};
504da6c28aaSamw  *
505da6c28aaSamw  * Consider the data tree:
506da6c28aaSamw  *
507da6c28aaSamw  *    +--------+
508da6c28aaSamw  *    |  user  |
509da6c28aaSamw  *    +--------+
510da6c28aaSamw  *    | name  ----> "fred" (the string is a different OUTER)
511da6c28aaSamw  *    | uid    |
512da6c28aaSamw  *    | gid    |
513da6c28aaSamw  *    | n_gids |    for example, 3
514da6c28aaSamw  *    | gids[0]|
515da6c28aaSamw  *    | gids[1]|
516da6c28aaSamw  *    | gids[2]|
517da6c28aaSamw  *    +--------+
518da6c28aaSamw  *
519da6c28aaSamw  * The OUTER construct in the Stub Data would be:
520da6c28aaSamw  *
521da6c28aaSamw  *    +---+---------+---------------------------------------------+
522da6c28aaSamw  *    |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
523da6c28aaSamw  *    +---+---------+---------------------------------------------+
524da6c28aaSamw  *         szing hdr|user |<-------------- user.cred ------------>|
525da6c28aaSamw  *                  |<--- fixed-size ---->|<----- conformant ---->|
526da6c28aaSamw  *
527da6c28aaSamw  * The ndr_typeinfo for struct user will have:
528da6c28aaSamw  *	pdu_fixed_size_part = 16	four long words (name uid gid n_gids)
529da6c28aaSamw  *	pdu_variable_size_part = 4	per element, sizeof gids[0]
530da6c28aaSamw  *
531da6c28aaSamw  * VARYING CONSTRUCTS -- NOT IMPLEMENTED
532da6c28aaSamw  *
533da6c28aaSamw  * VARYING constructs have the following header:
534da6c28aaSamw  *
535da6c28aaSamw  *	struct varying_header {
536da6c28aaSamw  *		ulong		first_is;
537da6c28aaSamw  *		ulong		length_is;
538da6c28aaSamw  *	};
539da6c28aaSamw  *
540da6c28aaSamw  * This indicates which interval of an array is significant.
541da6c28aaSamw  * Non-intersecting elements of the array are undefined and usually
542da6c28aaSamw  * zero-filled.  The first_is parameter for C arrays is always 0 for
543da6c28aaSamw  * the first element.
544da6c28aaSamw  *
545da6c28aaSamw  * N.B. Constructs may contain one CONFORMANT element, which is always
546da6c28aaSamw  * last, but may contain many VARYING elements, which can be anywhere.
547da6c28aaSamw  *
548da6c28aaSamw  * VARYING CONFORMANT constructs have the sizing headers arranged like
549da6c28aaSamw  * this:
550da6c28aaSamw  *
551da6c28aaSamw  *	struct conformant_header	all_conformant[N_CONFORMANT_DIM];
552da6c28aaSamw  *	struct varying_header		all_varying[N_VARYING_ELEMS_AND_DIMS];
553da6c28aaSamw  *
554da6c28aaSamw  * The sizing header is immediately followed by the values for the
555da6c28aaSamw  * construct.  Again, we don't support more than one dimension and
556da6c28aaSamw  * we don't support VARYING constructs at this time.
557da6c28aaSamw  *
558da6c28aaSamw  * A good example of a VARYING/CONFORMANT data structure is the UNIX
559da6c28aaSamw  * directory entry:
560da6c28aaSamw  *
561da6c28aaSamw  *	struct dirent {
562da6c28aaSamw  *		ushort		reclen;
563da6c28aaSamw  *		ushort		namlen;
564da6c28aaSamw  *		ulong		inum;
565da6c28aaSamw  *	    [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
566da6c28aaSamw  *		uchar		name[*];
567da6c28aaSamw  *	};
568da6c28aaSamw  *
569da6c28aaSamw  *
570da6c28aaSamw  * STRINGS ARE A SPECIAL CASE
571da6c28aaSamw  *
572da6c28aaSamw  * Strings are handled specially.  MS/RPC uses VARYING/CONFORMANT structures
573da6c28aaSamw  * for strings.  This is a simple one-dimensional variable-length array,
574da6c28aaSamw  * typically with its last element all zeroes.  We handle strings with the
575da6c28aaSamw  * header:
576da6c28aaSamw  *
577da6c28aaSamw  *	struct string_header {
578da6c28aaSamw  *		ulong		size_is;
579da6c28aaSamw  *		ulong		first_is;	// always 0
580da6c28aaSamw  *		ulong		length_is;	// always same as size_is
581da6c28aaSamw  *	};
582da6c28aaSamw  *
583da6c28aaSamw  * If general support for VARYING and VARYING/CONFORMANT mechanisms is
584da6c28aaSamw  * implemented, we probably won't need the strings special case.
585da6c28aaSamw  */
586da6c28aaSamw int
5878d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref)
588da6c28aaSamw {
5898d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
5908d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
591da6c28aaSamw 	int	is_varlen = ti->pdu_size_variable_part;
592da6c28aaSamw 	int	is_union = NDR_IS_UNION(ti);
593da6c28aaSamw 	int	is_string = NDR_IS_STRING(ti);
594da6c28aaSamw 	int	error = NDR_ERR_OUTER_PARAMS_BAD;
595da6c28aaSamw 	int	params;
596da6c28aaSamw 
597da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
598da6c28aaSamw 
599da6c28aaSamw 	NDR_TATTLE(outer_ref, "--OUTER--");
600da6c28aaSamw 
601da6c28aaSamw 	/* All outer constructs start on a mod4 (longword) boundary */
6028d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
603da6c28aaSamw 		return (0);		/* error already set */
604da6c28aaSamw 
605da6c28aaSamw 	/* Regardless of what it is, this is where it starts */
6068d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
607da6c28aaSamw 
608da6c28aaSamw 	if (is_union) {
609da6c28aaSamw 		error = NDR_ERR_OUTER_UNION_ILLEGAL;
610da6c28aaSamw 		NDR_SET_ERROR(outer_ref, error);
611da6c28aaSamw 		return (0);
612da6c28aaSamw 	}
613da6c28aaSamw 
614da6c28aaSamw 	switch (params) {
615da6c28aaSamw 	case NDR_F_NONE:
616da6c28aaSamw 		if (is_string)
6178d7e4166Sjose borrego 			return (ndr_outer_string(outer_ref));
618da6c28aaSamw 		if (is_varlen)
6198d7e4166Sjose borrego 			return (ndr_outer_conformant_construct(outer_ref));
620da6c28aaSamw 
6218d7e4166Sjose borrego 		return (ndr_outer_fixed(outer_ref));
622da6c28aaSamw 
623da6c28aaSamw 	case NDR_F_SIZE_IS:
624da6c28aaSamw 	case NDR_F_DIMENSION_IS:
625f96bd5c8SAlan Wright 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
626f96bd5c8SAlan Wright 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
627da6c28aaSamw 		if (is_varlen) {
628da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
629da6c28aaSamw 			break;
630da6c28aaSamw 		}
631da6c28aaSamw 
632f96bd5c8SAlan Wright 		if (params & NDR_F_SIZE_IS)
6338d7e4166Sjose borrego 			return (ndr_outer_conformant_array(outer_ref));
634da6c28aaSamw 		else
6358d7e4166Sjose borrego 			return (ndr_outer_fixed_array(outer_ref));
636da6c28aaSamw 
637da6c28aaSamw 	default:
638da6c28aaSamw 		error = NDR_ERR_OUTER_PARAMS_BAD;
639da6c28aaSamw 		break;
640da6c28aaSamw 	}
641da6c28aaSamw 
642da6c28aaSamw 	/*
643da6c28aaSamw 	 * If we get here, something is wrong. Most likely,
644da6c28aaSamw 	 * the params flags do not match.
645da6c28aaSamw 	 */
646da6c28aaSamw 	NDR_SET_ERROR(outer_ref, error);
647da6c28aaSamw 	return (0);
648da6c28aaSamw }
649da6c28aaSamw 
650da6c28aaSamw int
6518d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref)
652da6c28aaSamw {
6538d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
6548d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
6558d7e4166Sjose borrego 	ndr_ref_t	myref;
656da6c28aaSamw 	char 		*valp = NULL;
657da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
658da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
659da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
660da6c28aaSamw 	int		rc;
661da6c28aaSamw 	unsigned	n_hdr;
662da6c28aaSamw 	unsigned	n_fixed;
663da6c28aaSamw 	unsigned	n_variable;
664da6c28aaSamw 	unsigned	n_alloc;
665da6c28aaSamw 	unsigned	n_pdu_total;
666da6c28aaSamw 	int		params;
667da6c28aaSamw 
668da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
669da6c28aaSamw 
670da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
671da6c28aaSamw 	assert(params == NDR_F_NONE);
672da6c28aaSamw 
673da6c28aaSamw 	/* no header for this */
674da6c28aaSamw 	n_hdr = 0;
675da6c28aaSamw 
676da6c28aaSamw 	/* fixed part -- exactly one of these */
677da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
678da6c28aaSamw 	assert(n_fixed > 0);
679da6c28aaSamw 
680da6c28aaSamw 	/* variable part -- exactly none of these */
681da6c28aaSamw 	n_variable = 0;
682da6c28aaSamw 
683da6c28aaSamw 	/* sum them up to determine the PDU space required */
684da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
685da6c28aaSamw 
686da6c28aaSamw 	/* similar sum to determine how much local memory is required */
687da6c28aaSamw 	n_alloc = n_fixed + n_variable;
688da6c28aaSamw 
6898d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
690da6c28aaSamw 	if (!rc)
691da6c28aaSamw 		return (rc);		/* error already set */
692da6c28aaSamw 
6938d7e4166Sjose borrego 	switch (nds->m_op) {
694da6c28aaSamw 	case NDR_M_OP_MARSHALL:
695da6c28aaSamw 		valp = outer_ref->datum;
69696a62adaSjoyce mcintosh 		if (!valp) {
69796a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
69896a62adaSjoyce mcintosh 			return (0);
69996a62adaSjoyce mcintosh 		}
700f96bd5c8SAlan Wright 		if (outer_ref->backptr)
701da6c28aaSamw 			assert(valp == *outer_ref->backptr);
702da6c28aaSamw 		break;
703da6c28aaSamw 
704da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
7058d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
706da6c28aaSamw 		if (!valp) {
707da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
708da6c28aaSamw 			return (0);
709da6c28aaSamw 		}
710da6c28aaSamw 		if (outer_ref->backptr)
711da6c28aaSamw 			*outer_ref->backptr = valp;
712da6c28aaSamw 		outer_ref->datum = valp;
713da6c28aaSamw 		break;
714da6c28aaSamw 
715da6c28aaSamw 	default:
716da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
717da6c28aaSamw 		return (0);
718da6c28aaSamw 	}
719da6c28aaSamw 
720da6c28aaSamw 	bzero(&myref, sizeof (myref));
7218d7e4166Sjose borrego 	myref.stream = nds;
722da6c28aaSamw 	myref.enclosing = outer_ref;
723da6c28aaSamw 	myref.ti = outer_ref->ti;
724da6c28aaSamw 	myref.datum = outer_ref->datum;
725da6c28aaSamw 	myref.name = "FIXED-VALUE";
726da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
727da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
728da6c28aaSamw 
729da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset;
730da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
731da6c28aaSamw 
7328d7e4166Sjose borrego 	rc = ndr_inner(&myref);
733da6c28aaSamw 	if (!rc)
734da6c28aaSamw 		return (rc);		/* error already set */
735da6c28aaSamw 
7368d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
737da6c28aaSamw 	return (1);
738da6c28aaSamw }
739da6c28aaSamw 
740da6c28aaSamw int
7418d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref)
742da6c28aaSamw {
7438d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
7448d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
7458d7e4166Sjose borrego 	ndr_ref_t	myref;
746da6c28aaSamw 	char 		*valp = NULL;
747da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
748da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
749da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
750da6c28aaSamw 	int		rc;
751da6c28aaSamw 	unsigned	n_hdr;
752da6c28aaSamw 	unsigned	n_fixed;
753da6c28aaSamw 	unsigned	n_variable;
754da6c28aaSamw 	unsigned	n_alloc;
755da6c28aaSamw 	unsigned	n_pdu_total;
756da6c28aaSamw 	int		params;
757da6c28aaSamw 
758da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
759da6c28aaSamw 
760da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
761da6c28aaSamw 	assert(params == NDR_F_DIMENSION_IS);
762da6c28aaSamw 
763da6c28aaSamw 	/* no header for this */
764da6c28aaSamw 	n_hdr = 0;
765da6c28aaSamw 
766da6c28aaSamw 	/* fixed part -- exactly dimension_is of these */
767da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
768da6c28aaSamw 	assert(n_fixed > 0);
769da6c28aaSamw 
770da6c28aaSamw 	/* variable part -- exactly none of these */
771da6c28aaSamw 	n_variable = 0;
772da6c28aaSamw 
773da6c28aaSamw 	/* sum them up to determine the PDU space required */
774da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
775da6c28aaSamw 
776da6c28aaSamw 	/* similar sum to determine how much local memory is required */
777da6c28aaSamw 	n_alloc = n_fixed + n_variable;
778da6c28aaSamw 
7798d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
780da6c28aaSamw 	if (!rc)
781da6c28aaSamw 		return (rc);		/* error already set */
782da6c28aaSamw 
7838d7e4166Sjose borrego 	switch (nds->m_op) {
784da6c28aaSamw 	case NDR_M_OP_MARSHALL:
785da6c28aaSamw 		valp = outer_ref->datum;
78696a62adaSjoyce mcintosh 		if (!valp) {
78796a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
78896a62adaSjoyce mcintosh 			return (0);
78996a62adaSjoyce mcintosh 		}
790f96bd5c8SAlan Wright 		if (outer_ref->backptr)
791da6c28aaSamw 			assert(valp == *outer_ref->backptr);
792da6c28aaSamw 		break;
793da6c28aaSamw 
794da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
7958d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
796da6c28aaSamw 		if (!valp) {
797da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
798da6c28aaSamw 			return (0);
799da6c28aaSamw 		}
800da6c28aaSamw 		if (outer_ref->backptr)
801da6c28aaSamw 			*outer_ref->backptr = valp;
802da6c28aaSamw 		outer_ref->datum = valp;
803da6c28aaSamw 		break;
804da6c28aaSamw 
805da6c28aaSamw 	default:
806da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
807da6c28aaSamw 		return (0);
808da6c28aaSamw 	}
809da6c28aaSamw 
810da6c28aaSamw 	bzero(&myref, sizeof (myref));
8118d7e4166Sjose borrego 	myref.stream = nds;
812da6c28aaSamw 	myref.enclosing = outer_ref;
813da6c28aaSamw 	myref.ti = outer_ref->ti;
814da6c28aaSamw 	myref.datum = outer_ref->datum;
815da6c28aaSamw 	myref.name = "FIXED-ARRAY";
816da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
817da6c28aaSamw 	myref.inner_flags = NDR_F_DIMENSION_IS;
818da6c28aaSamw 	myref.dimension_is = outer_ref->dimension_is;
819da6c28aaSamw 
820da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset;
821da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
822da6c28aaSamw 
8238d7e4166Sjose borrego 	rc = ndr_inner(&myref);
824da6c28aaSamw 	if (!rc)
825da6c28aaSamw 		return (rc);		/* error already set */
826da6c28aaSamw 
8278d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
828da6c28aaSamw 	return (1);
829da6c28aaSamw }
830da6c28aaSamw 
831da6c28aaSamw int
8328d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref)
833da6c28aaSamw {
8348d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
8358d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
8368d7e4166Sjose borrego 	ndr_ref_t	myref;
837da6c28aaSamw 	char 		*valp = NULL;
838da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
839da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
840da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
841da6c28aaSamw 	unsigned long	size_is;
842da6c28aaSamw 	int		rc;
843da6c28aaSamw 	unsigned	n_hdr;
844da6c28aaSamw 	unsigned	n_fixed;
845da6c28aaSamw 	unsigned	n_variable;
846da6c28aaSamw 	unsigned	n_alloc;
847da6c28aaSamw 	unsigned	n_pdu_total;
848f96bd5c8SAlan Wright 	unsigned	n_ptr_offset;
849da6c28aaSamw 	int		params;
850da6c28aaSamw 
851da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
852da6c28aaSamw 
853da6c28aaSamw 	assert(!is_varlen && !is_string && !is_union);
854f96bd5c8SAlan Wright 	assert(params & NDR_F_SIZE_IS);
855da6c28aaSamw 
856da6c28aaSamw 	/* conformant header for this */
857da6c28aaSamw 	n_hdr = 4;
858da6c28aaSamw 
859da6c28aaSamw 	/* fixed part -- exactly none of these */
860da6c28aaSamw 	n_fixed = 0;
861da6c28aaSamw 
862da6c28aaSamw 	/* variable part -- exactly size_of of these */
863da6c28aaSamw 	/* notice that it is the **fixed** size of the ti */
864da6c28aaSamw 	n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
865da6c28aaSamw 
866da6c28aaSamw 	/* sum them up to determine the PDU space required */
867da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
868da6c28aaSamw 
869da6c28aaSamw 	/* similar sum to determine how much local memory is required */
870da6c28aaSamw 	n_alloc = n_fixed + n_variable;
871da6c28aaSamw 
8728d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
873da6c28aaSamw 	if (!rc)
874da6c28aaSamw 		return (rc);		/* error already set */
875da6c28aaSamw 
8768d7e4166Sjose borrego 	switch (nds->m_op) {
877da6c28aaSamw 	case NDR_M_OP_MARSHALL:
878da6c28aaSamw 		size_is = outer_ref->size_is;
8798d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
880da6c28aaSamw 		if (!rc)
881da6c28aaSamw 			return (0);	/* error already set */
882da6c28aaSamw 
883da6c28aaSamw 		valp = outer_ref->datum;
88496a62adaSjoyce mcintosh 		if (!valp) {
88596a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
88696a62adaSjoyce mcintosh 			return (0);
88796a62adaSjoyce mcintosh 		}
888f96bd5c8SAlan Wright 		if (outer_ref->backptr)
889da6c28aaSamw 			assert(valp == *outer_ref->backptr);
890f96bd5c8SAlan Wright 		n_ptr_offset = 4;
891da6c28aaSamw 		break;
892da6c28aaSamw 
893da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
894f96bd5c8SAlan Wright 		if (params & NDR_F_IS_REFERENCE) {
895f96bd5c8SAlan Wright 			size_is = outer_ref->size_is;
896f96bd5c8SAlan Wright 			n_ptr_offset = 0;
897f96bd5c8SAlan Wright 		} else {
898f96bd5c8SAlan Wright 			/* NDR_F_IS_POINTER */
899f96bd5c8SAlan Wright 			rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
900f96bd5c8SAlan Wright 			if (!rc)
901f96bd5c8SAlan Wright 				return (0);	/* error already set */
902f96bd5c8SAlan Wright 
903f96bd5c8SAlan Wright 			if (size_is != outer_ref->size_is) {
904f96bd5c8SAlan Wright 				NDR_SET_ERROR(outer_ref,
905f96bd5c8SAlan Wright 				    NDR_ERR_SIZE_IS_MISMATCH_PDU);
906f96bd5c8SAlan Wright 				return (0);
907f96bd5c8SAlan Wright 			}
908da6c28aaSamw 
909f96bd5c8SAlan Wright 			n_ptr_offset = 4;
910da6c28aaSamw 		}
911da6c28aaSamw 
9123ad684d6Sjb 		if (size_is > 0) {
9138d7e4166Sjose borrego 			valp = NDS_MALLOC(nds, n_alloc, outer_ref);
9143ad684d6Sjb 			if (!valp) {
9153ad684d6Sjb 				NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
9163ad684d6Sjb 				return (0);
9173ad684d6Sjb 			}
918da6c28aaSamw 		}
9193ad684d6Sjb 
920da6c28aaSamw 		if (outer_ref->backptr)
921da6c28aaSamw 			*outer_ref->backptr = valp;
922da6c28aaSamw 		outer_ref->datum = valp;
923da6c28aaSamw 		break;
924da6c28aaSamw 
925da6c28aaSamw 	default:
926da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
927da6c28aaSamw 		return (0);
928da6c28aaSamw 	}
929da6c28aaSamw 
930da6c28aaSamw 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
931da6c28aaSamw 	outer_ref->type_flags = NDR_F_NONE;
932da6c28aaSamw 	outer_ref->inner_flags = NDR_F_NONE;
933da6c28aaSamw 
9343ad684d6Sjb 	if (size_is > 0) {
9353ad684d6Sjb 		bzero(&myref, sizeof (myref));
9368d7e4166Sjose borrego 		myref.stream = nds;
9373ad684d6Sjb 		myref.enclosing = outer_ref;
9383ad684d6Sjb 		myref.ti = outer_ref->ti;
9393ad684d6Sjb 		myref.datum = outer_ref->datum;
9403ad684d6Sjb 		myref.name = "CONFORMANT-ARRAY";
9413ad684d6Sjb 		myref.outer_flags = NDR_F_NONE;
9423ad684d6Sjb 		myref.inner_flags = NDR_F_SIZE_IS;
9433ad684d6Sjb 		myref.size_is = outer_ref->size_is;
9443ad684d6Sjb 
9453ad684d6Sjb 		myref.inner_flags = NDR_F_DIMENSION_IS;		/* convenient */
9463ad684d6Sjb 		myref.dimension_is = outer_ref->size_is;	/* convenient */
9473ad684d6Sjb 
948f96bd5c8SAlan Wright 		myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
9493ad684d6Sjb 
9508d7e4166Sjose borrego 		rc = ndr_inner(&myref);
9513ad684d6Sjb 		if (!rc)
9523ad684d6Sjb 			return (rc);		/* error already set */
9533ad684d6Sjb 	}
954da6c28aaSamw 
9558d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
956da6c28aaSamw 	return (1);
957da6c28aaSamw }
958da6c28aaSamw 
959da6c28aaSamw int
9608d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
961da6c28aaSamw {
9628d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
9638d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
9648d7e4166Sjose borrego 	ndr_ref_t	myref;
965da6c28aaSamw 	char 		*valp = NULL;
966da6c28aaSamw 	int		is_varlen = ti->pdu_size_variable_part;
967da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
968da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
969da6c28aaSamw 	unsigned long	size_is;
970da6c28aaSamw 	int		rc;
971da6c28aaSamw 	unsigned	n_hdr;
972da6c28aaSamw 	unsigned	n_fixed;
973da6c28aaSamw 	unsigned	n_variable;
974da6c28aaSamw 	unsigned	n_alloc;
975da6c28aaSamw 	unsigned	n_pdu_total;
976da6c28aaSamw 	int		params;
977da6c28aaSamw 
978da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
979da6c28aaSamw 
980da6c28aaSamw 	assert(is_varlen && !is_string && !is_union);
981da6c28aaSamw 	assert(params == NDR_F_NONE);
982da6c28aaSamw 
983da6c28aaSamw 	/* conformant header for this */
984da6c28aaSamw 	n_hdr = 4;
985da6c28aaSamw 
986da6c28aaSamw 	/* fixed part -- exactly one of these */
987da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
988da6c28aaSamw 
989da6c28aaSamw 	/* variable part -- exactly size_of of these */
990da6c28aaSamw 	n_variable = 0;		/* 0 for the moment */
991da6c28aaSamw 
992da6c28aaSamw 	/* sum them up to determine the PDU space required */
993da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
994da6c28aaSamw 
995da6c28aaSamw 	/* similar sum to determine how much local memory is required */
996da6c28aaSamw 	n_alloc = n_fixed + n_variable;
997da6c28aaSamw 
998da6c28aaSamw 	/* For the moment, grow enough for the fixed-size part */
9998d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1000da6c28aaSamw 	if (!rc)
1001da6c28aaSamw 		return (rc);		/* error already set */
1002da6c28aaSamw 
10038d7e4166Sjose borrego 	switch (nds->m_op) {
1004da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1005da6c28aaSamw 		/*
1006da6c28aaSamw 		 * We don't know the size yet. We have to wait for
1007da6c28aaSamw 		 * it. Proceed with the fixed-size part, and await
10088d7e4166Sjose borrego 		 * the call to ndr_size_is().
1009da6c28aaSamw 		 */
1010da6c28aaSamw 		size_is = 0;
10118d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1012da6c28aaSamw 		if (!rc)
1013da6c28aaSamw 			return (0);	/* error already set */
1014da6c28aaSamw 
1015da6c28aaSamw 		valp = outer_ref->datum;
101696a62adaSjoyce mcintosh 		if (!valp) {
101796a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
101896a62adaSjoyce mcintosh 			return (0);
101996a62adaSjoyce mcintosh 		}
1020f96bd5c8SAlan Wright 		if (outer_ref->backptr)
1021da6c28aaSamw 			assert(valp == *outer_ref->backptr);
1022da6c28aaSamw 		break;
1023da6c28aaSamw 
1024da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1025da6c28aaSamw 		/*
1026da6c28aaSamw 		 * We know the size of the variable part because
1027da6c28aaSamw 		 * of the CONFORMANT header. We will verify
1028da6c28aaSamw 		 * the header against the [size_is(X)] advice
10298d7e4166Sjose borrego 		 * later when ndr_size_is() is called.
1030da6c28aaSamw 		 */
10318d7e4166Sjose borrego 		rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
1032da6c28aaSamw 		if (!rc)
1033da6c28aaSamw 			return (0);	/* error already set */
1034da6c28aaSamw 
1035da6c28aaSamw 		/* recalculate metrics */
1036da6c28aaSamw 		n_variable = size_is * ti->pdu_size_variable_part;
1037da6c28aaSamw 		n_pdu_total = n_hdr + n_fixed + n_variable;
1038da6c28aaSamw 		n_alloc = n_fixed + n_variable;
1039da6c28aaSamw 
10408d7e4166Sjose borrego 		rc = ndr_outer_grow(outer_ref, n_pdu_total);
1041da6c28aaSamw 		if (!rc)
1042da6c28aaSamw 			return (rc);		/* error already set */
1043da6c28aaSamw 
1044da6c28aaSamw 		outer_ref->size_is = size_is; /* verified later */
1045da6c28aaSamw 
10468d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1047da6c28aaSamw 		if (!valp) {
1048da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1049da6c28aaSamw 			return (0);
1050da6c28aaSamw 		}
1051da6c28aaSamw 		if (outer_ref->backptr)
1052da6c28aaSamw 			*outer_ref->backptr = valp;
1053da6c28aaSamw 		outer_ref->datum = valp;
1054da6c28aaSamw 		break;
1055da6c28aaSamw 
1056da6c28aaSamw 	default:
1057da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1058da6c28aaSamw 		return (0);
1059da6c28aaSamw 	}
1060da6c28aaSamw 
10613ad684d6Sjb 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
10623ad684d6Sjb 	outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
10633ad684d6Sjb 	outer_ref->inner_flags = NDR_F_NONE;   /* indicate pending */
10643ad684d6Sjb 
1065da6c28aaSamw 	bzero(&myref, sizeof (myref));
10668d7e4166Sjose borrego 	myref.stream = nds;
1067da6c28aaSamw 	myref.enclosing = outer_ref;
1068da6c28aaSamw 	myref.ti = outer_ref->ti;
1069da6c28aaSamw 	myref.datum = outer_ref->datum;
1070da6c28aaSamw 	myref.name = "CONFORMANT-CONSTRUCT";
1071da6c28aaSamw 	myref.outer_flags = NDR_F_NONE;
1072da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1073da6c28aaSamw 	myref.size_is = outer_ref->size_is;
1074da6c28aaSamw 
1075da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset + 4;
1076da6c28aaSamw 
10778d7e4166Sjose borrego 	rc = ndr_inner(&myref);
1078da6c28aaSamw 	if (!rc)
1079da6c28aaSamw 		return (rc);		/* error already set */
1080da6c28aaSamw 
10818d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1082da6c28aaSamw 
1083da6c28aaSamw 	if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
1084da6c28aaSamw 		NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
1085da6c28aaSamw 		return (0);
1086da6c28aaSamw 	}
1087da6c28aaSamw 
1088da6c28aaSamw 	return (1);
1089da6c28aaSamw }
1090da6c28aaSamw 
1091da6c28aaSamw int
10928d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref)
1093da6c28aaSamw {
10948d7e4166Sjose borrego 	ndr_stream_t 		*nds = ref->stream;
10958d7e4166Sjose borrego 	ndr_ref_t 		*outer_ref = nds->outer_current;
10968d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = outer_ref->ti;
1097da6c28aaSamw 	unsigned long		size_is;
1098da6c28aaSamw 	int			rc;
1099da6c28aaSamw 	unsigned		n_hdr;
1100da6c28aaSamw 	unsigned		n_fixed;
1101da6c28aaSamw 	unsigned		n_variable;
1102da6c28aaSamw 	unsigned		n_pdu_total;
1103da6c28aaSamw 
1104da6c28aaSamw 	assert(ref->inner_flags & NDR_F_SIZE_IS);
1105da6c28aaSamw 	size_is = ref->size_is;
1106da6c28aaSamw 
1107da6c28aaSamw 	if (outer_ref->type_flags != NDR_F_SIZE_IS) {
1108da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
1109da6c28aaSamw 		return (0);
1110da6c28aaSamw 	}
1111da6c28aaSamw 
1112da6c28aaSamw 	if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
1113da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
1114da6c28aaSamw 		return (0);
1115da6c28aaSamw 	}
1116da6c28aaSamw 
11178d7e4166Sjose borrego 	/* repeat metrics, see ndr_conformant_construct() above */
1118da6c28aaSamw 	n_hdr = 4;
1119da6c28aaSamw 	n_fixed = ti->pdu_size_fixed_part;
1120da6c28aaSamw 	n_variable = size_is * ti->pdu_size_variable_part;
1121da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
1122da6c28aaSamw 
11238d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1124da6c28aaSamw 	if (!rc)
1125da6c28aaSamw 		return (rc);		/* error already set */
1126da6c28aaSamw 
11278d7e4166Sjose borrego 	switch (nds->m_op) {
1128da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1129da6c28aaSamw 		/*
1130da6c28aaSamw 		 * We have to set the sizing header and extend
1131da6c28aaSamw 		 * the size of the PDU (already done).
1132da6c28aaSamw 		 */
11338d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1134da6c28aaSamw 		if (!rc)
1135da6c28aaSamw 			return (0);	/* error already set */
1136da6c28aaSamw 		break;
1137da6c28aaSamw 
1138da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1139da6c28aaSamw 		/*
11408d7e4166Sjose borrego 		 * Allocation done during ndr_conformant_construct().
1141da6c28aaSamw 		 * All we are doing here is verifying that the
1142da6c28aaSamw 		 * intended size (ref->size_is) matches the sizing header.
1143da6c28aaSamw 		 */
1144da6c28aaSamw 		if (size_is != outer_ref->size_is) {
1145da6c28aaSamw 			NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
1146da6c28aaSamw 			return (0);
1147da6c28aaSamw 		}
1148da6c28aaSamw 		break;
1149da6c28aaSamw 
1150da6c28aaSamw 	default:
1151da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1152da6c28aaSamw 		return (0);
1153da6c28aaSamw 	}
1154da6c28aaSamw 
1155da6c28aaSamw 	outer_ref->inner_flags |= NDR_F_SIZE_IS;
1156da6c28aaSamw 	outer_ref->size_is = ref->size_is;
1157da6c28aaSamw 	return (1);
1158da6c28aaSamw }
1159da6c28aaSamw 
1160da6c28aaSamw int
11618d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref)
1162da6c28aaSamw {
11638d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
11648d7e4166Sjose borrego 	ndr_typeinfo_t 	*ti = outer_ref->ti;
11658d7e4166Sjose borrego 	ndr_ref_t	myref;
1166da6c28aaSamw 	char 		*valp = NULL;
1167da6c28aaSamw 	unsigned	is_varlen = ti->pdu_size_variable_part;
1168da6c28aaSamw 	int		is_union = NDR_IS_UNION(ti);
1169da6c28aaSamw 	int		is_string = NDR_IS_STRING(ti);
1170da6c28aaSamw 	int		rc;
1171da6c28aaSamw 	unsigned	n_zeroes;
1172da6c28aaSamw 	unsigned	ix;
1173da6c28aaSamw 	unsigned long	size_is;
1174da6c28aaSamw 	unsigned long	first_is;
1175da6c28aaSamw 	unsigned long	length_is;
1176da6c28aaSamw 	unsigned	n_hdr;
1177da6c28aaSamw 	unsigned	n_fixed;
1178da6c28aaSamw 	unsigned	n_variable;
1179da6c28aaSamw 	unsigned	n_alloc;
1180da6c28aaSamw 	unsigned	n_pdu_total;
1181da6c28aaSamw 	int		params;
1182da6c28aaSamw 
1183da6c28aaSamw 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1184da6c28aaSamw 
1185da6c28aaSamw 	assert(is_varlen && is_string && !is_union);
1186da6c28aaSamw 	assert(params == NDR_F_NONE);
1187da6c28aaSamw 
1188da6c28aaSamw 	/* string header for this: size_is first_is length_is */
1189da6c28aaSamw 	n_hdr = 12;
1190da6c28aaSamw 
1191da6c28aaSamw 	/* fixed part -- exactly none of these */
1192da6c28aaSamw 	n_fixed = 0;
1193da6c28aaSamw 
11948d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_hdr))
1195da6c28aaSamw 		return (0);		/* error already set */
1196da6c28aaSamw 
11978d7e4166Sjose borrego 	switch (nds->m_op) {
1198da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1199da6c28aaSamw 		valp = outer_ref->datum;
120096a62adaSjoyce mcintosh 		if (!valp) {
120196a62adaSjoyce mcintosh 			NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
120296a62adaSjoyce mcintosh 			return (0);
120396a62adaSjoyce mcintosh 		}
1204da6c28aaSamw 
1205da6c28aaSamw 		if (outer_ref->backptr)
1206da6c28aaSamw 			assert(valp == *outer_ref->backptr);
1207da6c28aaSamw 
1208da6c28aaSamw 		if (ti == &ndt_s_wchar) {
1209da6c28aaSamw 			/*
1210a0aa776eSAlan Wright 			 * size_is is the number of characters in the
1211a0aa776eSAlan Wright 			 * (multibyte) string, including the null.
12123299f39fSGordon Ross 			 * In other words, symbols, not bytes.
1213da6c28aaSamw 			 */
12143299f39fSGordon Ross 			size_t wlen;
12153299f39fSGordon Ross 			wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
12163299f39fSGordon Ross 			if (wlen == (size_t)-1) {
12173299f39fSGordon Ross 				/* illegal sequence error? */
1218da6c28aaSamw 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1219da6c28aaSamw 				return (0);
1220da6c28aaSamw 			}
12213299f39fSGordon Ross 			if ((nds->flags & NDS_F_NONULL) == 0)
12223299f39fSGordon Ross 				wlen++;
12233299f39fSGordon Ross 			if (wlen > NDR_STRING_MAX) {
12243299f39fSGordon Ross 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
12253299f39fSGordon Ross 				return (0);
12263299f39fSGordon Ross 			}
12273299f39fSGordon Ross 			size_is = wlen;
1228da6c28aaSamw 		} else {
1229da6c28aaSamw 			valp = outer_ref->datum;
1230da6c28aaSamw 			n_zeroes = 0;
1231f96bd5c8SAlan Wright 			for (ix = 0; ix < NDR_STRING_MAX; ix++) {
1232da6c28aaSamw 				if (valp[ix] == 0) {
1233da6c28aaSamw 					n_zeroes++;
1234da6c28aaSamw 					if (n_zeroes >= is_varlen &&
1235da6c28aaSamw 					    ix % is_varlen == 0) {
1236da6c28aaSamw 						break;
1237da6c28aaSamw 					}
1238da6c28aaSamw 				} else {
1239da6c28aaSamw 					n_zeroes = 0;
1240da6c28aaSamw 				}
1241da6c28aaSamw 			}
1242f96bd5c8SAlan Wright 			if (ix >= NDR_STRING_MAX) {
1243da6c28aaSamw 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1244da6c28aaSamw 				return (0);
1245da6c28aaSamw 			}
1246da6c28aaSamw 			size_is = ix+1;
1247da6c28aaSamw 		}
1248da6c28aaSamw 
1249da6c28aaSamw 		first_is = 0;
125055bf511dSas 
12518d7e4166Sjose borrego 		if (nds->flags & NDS_F_NOTERM)
125255bf511dSas 			length_is = size_is - 1;
125355bf511dSas 		else
125455bf511dSas 			length_is = size_is;
1255da6c28aaSamw 
12568d7e4166Sjose borrego 		if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
12578d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
12588d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
1259da6c28aaSamw 			return (0);		/* error already set */
1260da6c28aaSamw 		break;
1261da6c28aaSamw 
1262da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
12638d7e4166Sjose borrego 		if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
12648d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
12658d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
1266da6c28aaSamw 			return (0);		/* error already set */
1267da6c28aaSamw 
1268da6c28aaSamw 		/*
1269da6c28aaSamw 		 * In addition to the first_is check, we used to check that
1270da6c28aaSamw 		 * size_is or size_is-1 was equal to length_is but Windows95
1271da6c28aaSamw 		 * doesn't conform to this "rule" (see variable part below).
1272da6c28aaSamw 		 * The srvmgr tool for Windows95 sent the following values
1273da6c28aaSamw 		 * for a path string:
1274da6c28aaSamw 		 *
1275da6c28aaSamw 		 *	size_is   = 261 (0x105)
1276da6c28aaSamw 		 *	first_is  = 0
1277da6c28aaSamw 		 *	length_is = 53  (0x35)
1278da6c28aaSamw 		 *
1279da6c28aaSamw 		 * The length_is was correct (for the given path) but the
1280da6c28aaSamw 		 * size_is was the maximum path length rather than being
1281da6c28aaSamw 		 * related to length_is.
1282da6c28aaSamw 		 */
1283da6c28aaSamw 		if (first_is != 0) {
1284da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1285da6c28aaSamw 			return (0);
1286da6c28aaSamw 		}
1287da6c28aaSamw 
1288da6c28aaSamw 		if (ti == &ndt_s_wchar) {
1289da6c28aaSamw 			/*
1290da6c28aaSamw 			 * Decoding Unicode to UTF-8; we need to allow
1291da6c28aaSamw 			 * for the maximum possible char size. It would
1292da6c28aaSamw 			 * be nice to use mbequiv_strlen but the string
1293da6c28aaSamw 			 * may not be null terminated.
1294da6c28aaSamw 			 */
12953299f39fSGordon Ross 			n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
1296da6c28aaSamw 		} else {
1297da6c28aaSamw 			n_alloc = (size_is + 1) * is_varlen;
1298da6c28aaSamw 		}
1299da6c28aaSamw 
13008d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1301da6c28aaSamw 		if (!valp) {
1302da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1303da6c28aaSamw 			return (0);
1304da6c28aaSamw 		}
1305da6c28aaSamw 
1306da6c28aaSamw 		bzero(valp, (size_is+1) * is_varlen);
1307da6c28aaSamw 
1308da6c28aaSamw 		if (outer_ref->backptr)
1309da6c28aaSamw 			*outer_ref->backptr = valp;
1310da6c28aaSamw 		outer_ref->datum = valp;
1311da6c28aaSamw 		break;
1312da6c28aaSamw 
1313da6c28aaSamw 	default:
1314da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1315da6c28aaSamw 		return (0);
1316da6c28aaSamw 	}
1317da6c28aaSamw 
1318da6c28aaSamw 	/*
1319da6c28aaSamw 	 * Variable part - exactly length_is of these.
1320da6c28aaSamw 	 *
1321da6c28aaSamw 	 * Usually, length_is is same as size_is and includes nul.
1322da6c28aaSamw 	 * Some protocols use length_is = size_is-1, and length_is does
1323da6c28aaSamw 	 * not include the nul (which is more consistent with DCE spec).
1324da6c28aaSamw 	 * If the length_is is 0, there is no data following the
1325da6c28aaSamw 	 * sizing header, regardless of size_is.
1326da6c28aaSamw 	 */
1327da6c28aaSamw 	n_variable = length_is * is_varlen;
1328da6c28aaSamw 
1329da6c28aaSamw 	/* sum them up to determine the PDU space required */
1330da6c28aaSamw 	n_pdu_total = n_hdr + n_fixed + n_variable;
1331da6c28aaSamw 
1332da6c28aaSamw 	/* similar sum to determine how much local memory is required */
1333da6c28aaSamw 	n_alloc = n_fixed + n_variable;
1334da6c28aaSamw 
13358d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1336da6c28aaSamw 	if (!rc)
1337da6c28aaSamw 		return (rc);		/* error already set */
1338da6c28aaSamw 
1339da6c28aaSamw 	if (length_is > 0) {
1340da6c28aaSamw 		bzero(&myref, sizeof (myref));
13418d7e4166Sjose borrego 		myref.stream = nds;
1342da6c28aaSamw 		myref.enclosing = outer_ref;
1343da6c28aaSamw 		myref.ti = outer_ref->ti;
1344da6c28aaSamw 		myref.datum = outer_ref->datum;
1345da6c28aaSamw 		myref.name = "OUTER-STRING";
1346da6c28aaSamw 		myref.outer_flags = NDR_F_IS_STRING;
1347da6c28aaSamw 		myref.inner_flags = NDR_F_NONE;
1348da6c28aaSamw 
1349da6c28aaSamw 		/*
13508d7e4166Sjose borrego 		 * Set up size_is and strlen_is for ndr_s_wchar.
1351da6c28aaSamw 		 */
1352dc20a302Sas 		myref.size_is = size_is;
1353da6c28aaSamw 		myref.strlen_is = length_is;
1354da6c28aaSamw 	}
1355da6c28aaSamw 
1356da6c28aaSamw 	myref.pdu_offset = outer_ref->pdu_offset + 12;
1357da6c28aaSamw 
1358da6c28aaSamw 	/*
1359da6c28aaSamw 	 * Don't try to decode empty strings.
1360da6c28aaSamw 	 */
1361da6c28aaSamw 	if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
13628d7e4166Sjose borrego 		nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1363da6c28aaSamw 		return (1);
1364da6c28aaSamw 	}
1365da6c28aaSamw 
1366da6c28aaSamw 	if ((size_is != 0) && (length_is != 0)) {
13678d7e4166Sjose borrego 		rc = ndr_inner(&myref);
1368da6c28aaSamw 		if (!rc)
1369da6c28aaSamw 			return (rc);		/* error already set */
1370da6c28aaSamw 	}
1371da6c28aaSamw 
13728d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1373da6c28aaSamw 	return (1);
1374da6c28aaSamw }
1375da6c28aaSamw 
1376da6c28aaSamw int
13778d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
1378da6c28aaSamw     unsigned long *sizing_p)
1379da6c28aaSamw {
13808d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
13818d7e4166Sjose borrego 	unsigned long	pdu_offset;
13828d7e4166Sjose borrego 	int		rc;
1383da6c28aaSamw 
1384da6c28aaSamw 	pdu_offset = outer_ref->pdu_offset + offset;
1385da6c28aaSamw 
13868d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
13878d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
13888d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1389da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1390da6c28aaSamw 		return (0);
1391da6c28aaSamw 	}
1392da6c28aaSamw 
13938d7e4166Sjose borrego 	switch (nds->m_op) {
1394da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1395da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1396da6c28aaSamw 		return (0);
1397da6c28aaSamw 
1398da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
13998d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14008d7e4166Sjose borrego 		    nds->swap, outer_ref);
1401da6c28aaSamw 		break;
1402da6c28aaSamw 
1403da6c28aaSamw 	default:
1404da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1405da6c28aaSamw 		return (0);
1406da6c28aaSamw 	}
1407da6c28aaSamw 
1408da6c28aaSamw 	return (rc);
1409da6c28aaSamw }
1410da6c28aaSamw 
1411da6c28aaSamw int
14128d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
1413da6c28aaSamw     unsigned long *sizing_p)
1414da6c28aaSamw {
14158d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
14168d7e4166Sjose borrego 	unsigned long	pdu_offset;
14178d7e4166Sjose borrego 	int		rc;
1418da6c28aaSamw 
1419da6c28aaSamw 	pdu_offset = outer_ref->pdu_offset + offset;
1420da6c28aaSamw 
14218d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
14228d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
14238d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1424da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1425da6c28aaSamw 		return (0);
1426da6c28aaSamw 	}
1427da6c28aaSamw 
14288d7e4166Sjose borrego 	switch (nds->m_op) {
1429da6c28aaSamw 	case NDR_M_OP_MARSHALL:
14308d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14318d7e4166Sjose borrego 		    nds->swap, outer_ref);
1432da6c28aaSamw 		break;
1433da6c28aaSamw 
1434da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1435da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1436da6c28aaSamw 		return (0);
1437da6c28aaSamw 
1438da6c28aaSamw 	default:
1439da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1440da6c28aaSamw 		return (0);
1441da6c28aaSamw 	}
1442da6c28aaSamw 
1443da6c28aaSamw 	return (rc);
1444da6c28aaSamw }
1445da6c28aaSamw 
1446da6c28aaSamw /*
1447da6c28aaSamw  * All OUTER constructs begin on a mod4 (dword) boundary - except
1448da6c28aaSamw  * for the ones that don't: some MSRPC calls appear to use word or
1449da6c28aaSamw  * packed alignment.  Strings appear to be dword aligned.
1450da6c28aaSamw  */
1451da6c28aaSamw int
14528d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref)
1453da6c28aaSamw {
14548d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
14558d7e4166Sjose borrego 	int		rc;
14568d7e4166Sjose borrego 	unsigned	n_pad;
14578d7e4166Sjose borrego 	unsigned	align;
1458da6c28aaSamw 
1459da6c28aaSamw 	if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1460da6c28aaSamw 		align = outer_ref->ti->alignment;
14618d7e4166Sjose borrego 		n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
1462da6c28aaSamw 	} else {
14638d7e4166Sjose borrego 		n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
1464da6c28aaSamw 	}
1465da6c28aaSamw 
1466da6c28aaSamw 	if (n_pad == 0)
1467da6c28aaSamw 		return (1);	/* already aligned, often the case */
1468da6c28aaSamw 
14698d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_pad))
1470da6c28aaSamw 		return (0);	/* error already set */
1471da6c28aaSamw 
14728d7e4166Sjose borrego 	switch (nds->m_op) {
1473da6c28aaSamw 	case NDR_M_OP_MARSHALL:
14748d7e4166Sjose borrego 		rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
1475da6c28aaSamw 		if (!rc) {
1476da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1477da6c28aaSamw 			return (0);
1478da6c28aaSamw 		}
1479da6c28aaSamw 		break;
1480da6c28aaSamw 
1481da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1482da6c28aaSamw 		break;
1483da6c28aaSamw 
1484da6c28aaSamw 	default:
1485da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1486da6c28aaSamw 		return (0);
1487da6c28aaSamw 	}
1488da6c28aaSamw 
14898d7e4166Sjose borrego 	nds->pdu_scan_offset += n_pad;
1490da6c28aaSamw 	return (1);
1491da6c28aaSamw }
1492da6c28aaSamw 
1493da6c28aaSamw int
14948d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
1495da6c28aaSamw {
14968d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
14978d7e4166Sjose borrego 	unsigned long	pdu_want_size;
14988d7e4166Sjose borrego 	int		rc, is_ok = 0;
1499da6c28aaSamw 
15008d7e4166Sjose borrego 	pdu_want_size = nds->pdu_scan_offset + n_total;
1501da6c28aaSamw 
15028d7e4166Sjose borrego 	if (pdu_want_size <= nds->pdu_max_size) {
1503da6c28aaSamw 		is_ok = 1;
1504da6c28aaSamw 	}
1505da6c28aaSamw 
15068d7e4166Sjose borrego 	switch (nds->m_op) {
1507da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1508da6c28aaSamw 		if (is_ok)
1509da6c28aaSamw 			break;
15108d7e4166Sjose borrego 		rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
1511da6c28aaSamw 		if (!rc) {
1512da6c28aaSamw 			NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1513da6c28aaSamw 			return (0);
1514da6c28aaSamw 		}
1515da6c28aaSamw 		break;
1516da6c28aaSamw 
1517da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1518da6c28aaSamw 		if (is_ok)
1519da6c28aaSamw 			break;
1520da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1521da6c28aaSamw 		return (0);
1522da6c28aaSamw 
1523da6c28aaSamw 	default:
1524da6c28aaSamw 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1525da6c28aaSamw 		return (0);
1526da6c28aaSamw 	}
1527da6c28aaSamw 
15288d7e4166Sjose borrego 	if (nds->pdu_size < pdu_want_size)
15298d7e4166Sjose borrego 		nds->pdu_size = pdu_want_size;
1530da6c28aaSamw 
1531da6c28aaSamw 	outer_ref->pdu_end_offset = pdu_want_size;
1532da6c28aaSamw 	return (1);
1533da6c28aaSamw }
1534da6c28aaSamw 
1535da6c28aaSamw /*
1536da6c28aaSamw  * INNER ELEMENTS
1537da6c28aaSamw  *
1538da6c28aaSamw  * The local datum (arg_ref->datum) already exists, there is no need to
1539da6c28aaSamw  * malloc() it.  The datum should point at a member of a structure.
1540da6c28aaSamw  *
15418d7e4166Sjose borrego  * For the most part, ndr_inner() and its helpers are just a sanity
1542da6c28aaSamw  * check.  The underlying ti->ndr_func() could be called immediately
1543da6c28aaSamw  * for non-pointer elements.  For the sake of robustness, we detect
1544da6c28aaSamw  * run-time errors here.  Most of the situations this protects against
1545da6c28aaSamw  * have already been checked by the IDL compiler.  This is also a
1546da6c28aaSamw  * common point for processing of all data, and so is a convenient
1547da6c28aaSamw  * place to work from for debugging.
1548da6c28aaSamw  */
1549da6c28aaSamw int
15508d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref)
1551da6c28aaSamw {
15528d7e4166Sjose borrego 	ndr_typeinfo_t 	*ti = arg_ref->ti;
1553da6c28aaSamw 	int	is_varlen = ti->pdu_size_variable_part;
1554da6c28aaSamw 	int	is_union = NDR_IS_UNION(ti);
1555da6c28aaSamw 	int	error = NDR_ERR_INNER_PARAMS_BAD;
1556da6c28aaSamw 	int	params;
1557da6c28aaSamw 
1558da6c28aaSamw 	params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1559da6c28aaSamw 
1560da6c28aaSamw 	switch (params) {
1561da6c28aaSamw 	case NDR_F_NONE:
1562da6c28aaSamw 		if (is_union) {
1563da6c28aaSamw 			error = NDR_ERR_SWITCH_VALUE_MISSING;
1564da6c28aaSamw 			break;
1565da6c28aaSamw 		}
1566da6c28aaSamw 		return (*ti->ndr_func)(arg_ref);
1567da6c28aaSamw 
1568da6c28aaSamw 	case NDR_F_SIZE_IS:
1569da6c28aaSamw 	case NDR_F_DIMENSION_IS:
1570da6c28aaSamw 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:   /* pointer to something */
1571da6c28aaSamw 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1572da6c28aaSamw 		if (is_varlen) {
1573da6c28aaSamw 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1574da6c28aaSamw 			break;
1575da6c28aaSamw 		}
1576da6c28aaSamw 		if (is_union) {
1577da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1578da6c28aaSamw 			break;
1579da6c28aaSamw 		}
1580da6c28aaSamw 		if (params & NDR_F_IS_POINTER)
15818d7e4166Sjose borrego 			return (ndr_inner_pointer(arg_ref));
1582da6c28aaSamw 		else if (params & NDR_F_IS_REFERENCE)
15838d7e4166Sjose borrego 			return (ndr_inner_reference(arg_ref));
1584da6c28aaSamw 		else
15858d7e4166Sjose borrego 			return (ndr_inner_array(arg_ref));
1586da6c28aaSamw 
1587da6c28aaSamw 	case NDR_F_IS_POINTER:	/* type is pointer to one something */
1588da6c28aaSamw 		if (is_union) {
1589da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1590da6c28aaSamw 			break;
1591da6c28aaSamw 		}
15928d7e4166Sjose borrego 		return (ndr_inner_pointer(arg_ref));
1593da6c28aaSamw 
1594da6c28aaSamw 	case NDR_F_IS_REFERENCE:	/* type is pointer to one something */
1595da6c28aaSamw 		if (is_union) {
1596da6c28aaSamw 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1597da6c28aaSamw 			break;
1598da6c28aaSamw 		}
15998d7e4166Sjose borrego 		return (ndr_inner_reference(arg_ref));
1600da6c28aaSamw 
1601da6c28aaSamw 	case NDR_F_SWITCH_IS:
1602da6c28aaSamw 		if (!is_union) {
1603da6c28aaSamw 			error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1604da6c28aaSamw 			break;
1605da6c28aaSamw 		}
1606da6c28aaSamw 		return (*ti->ndr_func)(arg_ref);
1607da6c28aaSamw 
1608da6c28aaSamw 	default:
1609da6c28aaSamw 		error = NDR_ERR_INNER_PARAMS_BAD;
1610da6c28aaSamw 		break;
1611da6c28aaSamw 	}
1612da6c28aaSamw 
1613da6c28aaSamw 	/*
1614da6c28aaSamw 	 * If we get here, something is wrong. Most likely,
1615da6c28aaSamw 	 * the params flags do not match
1616da6c28aaSamw 	 */
1617da6c28aaSamw 	NDR_SET_ERROR(arg_ref, error);
1618da6c28aaSamw 	return (0);
1619da6c28aaSamw }
1620da6c28aaSamw 
1621da6c28aaSamw int
16228d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref)
1623da6c28aaSamw {
16248d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1625da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
16268d7e4166Sjose borrego 	char 		**valpp = (char **)arg_ref->datum;
16278d7e4166Sjose borrego 	ndr_ref_t 	*outer_ref;
1628da6c28aaSamw 
16298d7e4166Sjose borrego 	if (!ndr__ulong(arg_ref))
1630da6c28aaSamw 		return (0);	/* error */
1631da6c28aaSamw 	if (!*valpp)
1632da6c28aaSamw 		return (1);	/* NULL pointer */
1633da6c28aaSamw 
16348d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1635da6c28aaSamw 	if (!outer_ref)
1636da6c28aaSamw 		return (0);	/* error already set */
1637da6c28aaSamw 
1638f96bd5c8SAlan Wright 	/*
1639f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1640f96bd5c8SAlan Wright 	 * Retain pointer flag for conformant arrays.
1641f96bd5c8SAlan Wright 	 */
1642da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1643f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1644f96bd5c8SAlan Wright 		outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1645f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET
1646da6c28aaSamw 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1647da6c28aaSamw 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1648da6c28aaSamw 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1649da6c28aaSamw 	}
1650f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */
1651da6c28aaSamw 
1652da6c28aaSamw 	outer_ref->backptr = valpp;
1653da6c28aaSamw 
16548d7e4166Sjose borrego 	switch (nds->m_op) {
1655da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1656da6c28aaSamw 		outer_ref->datum = *valpp;
1657da6c28aaSamw 		break;
1658da6c28aaSamw 
1659da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1660da6c28aaSamw 		/*
1661da6c28aaSamw 		 * This is probably wrong if the application allocated
1662da6c28aaSamw 		 * memory in advance.  Indicate no value for now.
1663da6c28aaSamw 		 * ONC RPC handles this case.
1664da6c28aaSamw 		 */
1665da6c28aaSamw 		*valpp = 0;
1666da6c28aaSamw 		outer_ref->datum = 0;
1667da6c28aaSamw 		break;
1668da6c28aaSamw 	}
1669da6c28aaSamw 
1670da6c28aaSamw 	return (1);		/* pointer dereference scheduled */
1671da6c28aaSamw }
1672da6c28aaSamw 
1673da6c28aaSamw int
16748d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref)
1675da6c28aaSamw {
16768d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1677da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
16788d7e4166Sjose borrego 	char		**valpp = (char **)arg_ref->datum;
16798d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
1680da6c28aaSamw 
16818d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1682da6c28aaSamw 	if (!outer_ref)
1683da6c28aaSamw 		return (0);	/* error already set */
1684da6c28aaSamw 
1685f96bd5c8SAlan Wright 	/*
1686f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1687f96bd5c8SAlan Wright 	 * Retain reference flag for conformant arrays.
1688f96bd5c8SAlan Wright 	 */
1689da6c28aaSamw 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1690f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1691f96bd5c8SAlan Wright 		outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1692da6c28aaSamw #ifdef NDR_INNER_REF_NOT_YET
1693da6c28aaSamw 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1694da6c28aaSamw 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1695da6c28aaSamw 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1696da6c28aaSamw 	}
1697da6c28aaSamw #endif /* NDR_INNER_REF_NOT_YET */
1698da6c28aaSamw 
1699da6c28aaSamw 	outer_ref->backptr = valpp;
1700da6c28aaSamw 
17018d7e4166Sjose borrego 	switch (nds->m_op) {
1702da6c28aaSamw 	case NDR_M_OP_MARSHALL:
1703da6c28aaSamw 		outer_ref->datum = *valpp;
1704da6c28aaSamw 		break;
1705da6c28aaSamw 
1706da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
1707da6c28aaSamw 		/*
1708da6c28aaSamw 		 * This is probably wrong if the application allocated
1709da6c28aaSamw 		 * memory in advance.  Indicate no value for now.
1710da6c28aaSamw 		 * ONC RPC handles this case.
1711da6c28aaSamw 		 */
1712da6c28aaSamw 		*valpp = 0;
1713da6c28aaSamw 		outer_ref->datum = 0;
1714da6c28aaSamw 		break;
1715da6c28aaSamw 	}
1716da6c28aaSamw 
1717da6c28aaSamw 	return (1);		/* pointer dereference scheduled */
1718da6c28aaSamw }
1719da6c28aaSamw 
1720da6c28aaSamw int
17218d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref)
1722da6c28aaSamw {
17238d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = encl_ref->ti;
17248d7e4166Sjose borrego 	ndr_ref_t		myref;
1725da6c28aaSamw 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1726da6c28aaSamw 	unsigned long		n_elem;
1727da6c28aaSamw 	unsigned long		i;
1728da6c28aaSamw 	char			name[30];
1729da6c28aaSamw 
1730da6c28aaSamw 	if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1731da6c28aaSamw 		/* now is the time to check/set size */
17328d7e4166Sjose borrego 		if (!ndr_size_is(encl_ref))
1733da6c28aaSamw 			return (0);	/* error already set */
1734da6c28aaSamw 		n_elem = encl_ref->size_is;
1735da6c28aaSamw 	} else {
1736da6c28aaSamw 		assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1737da6c28aaSamw 		n_elem = encl_ref->dimension_is;
1738da6c28aaSamw 	}
1739da6c28aaSamw 
1740da6c28aaSamw 	bzero(&myref, sizeof (myref));
1741da6c28aaSamw 	myref.enclosing = encl_ref;
1742da6c28aaSamw 	myref.stream = encl_ref->stream;
1743da6c28aaSamw 	myref.packed_alignment = 0;
1744da6c28aaSamw 	myref.ti = ti;
1745da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1746da6c28aaSamw 
1747da6c28aaSamw 	for (i = 0; i < n_elem; i++) {
17483299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
1749da6c28aaSamw 		myref.name = name;
1750da6c28aaSamw 		myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1751da6c28aaSamw 		myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1752da6c28aaSamw 
17538d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1754da6c28aaSamw 			return (0);
1755da6c28aaSamw 	}
1756da6c28aaSamw 
1757da6c28aaSamw 	return (1);
1758da6c28aaSamw }
1759da6c28aaSamw 
1760da6c28aaSamw 
1761da6c28aaSamw /*
1762da6c28aaSamw  * BASIC TYPES
1763da6c28aaSamw  */
1764da6c28aaSamw #define	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
17658d7e4166Sjose borrego     extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
17668d7e4166Sjose borrego     ndr_typeinfo_t ndt_##TYPE = { \
1767da6c28aaSamw 	1,		/* NDR version */ \
1768da6c28aaSamw 	(SIZE)-1,	/* alignment */ \
1769da6c28aaSamw 	NDR_F_NONE,	/* flags */ \
17708d7e4166Sjose borrego 	ndr_##TYPE,	/* ndr_func */ \
1771da6c28aaSamw 	SIZE,		/* pdu_size_fixed_part */ \
1772da6c28aaSamw 	0,		/* pdu_size_variable_part */ \
1773da6c28aaSamw 	SIZE,		/* c_size_fixed_part */ \
1774da6c28aaSamw 	0,		/* c_size_variable_part */ \
1775da6c28aaSamw 	}; \
17768d7e4166Sjose borrego     int ndr_##TYPE(struct ndr_reference *ref) { \
17778d7e4166Sjose borrego 	return (ndr_basic_integer(ref, SIZE)); \
1778da6c28aaSamw }
1779da6c28aaSamw 
1780da6c28aaSamw #define	MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
17818d7e4166Sjose borrego     extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
17828d7e4166Sjose borrego     ndr_typeinfo_t ndt_s##TYPE = { \
1783da6c28aaSamw 	1,		/* NDR version */ \
1784da6c28aaSamw 	(SIZE)-1,	/* alignment */ \
1785da6c28aaSamw 	NDR_F_STRING,	/* flags */ \
17868d7e4166Sjose borrego 	ndr_s##TYPE,	/* ndr_func */ \
1787da6c28aaSamw 	0,		/* pdu_size_fixed_part */ \
1788da6c28aaSamw 	SIZE,		/* pdu_size_variable_part */ \
1789da6c28aaSamw 	0,		/* c_size_fixed_part */ \
1790da6c28aaSamw 	SIZE,		/* c_size_variable_part */ \
1791da6c28aaSamw 	}; \
17928d7e4166Sjose borrego     int ndr_s##TYPE(struct ndr_reference *ref) { \
17938d7e4166Sjose borrego 	return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
1794da6c28aaSamw }
1795da6c28aaSamw 
1796da6c28aaSamw #define	MAKE_BASIC_TYPE(TYPE, SIZE) \
1797da6c28aaSamw 	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1798da6c28aaSamw 	MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1799da6c28aaSamw 
18008d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned);
18018d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
1802da6c28aaSamw 
18033299f39fSGordon Ross /* Comments to be nice to those searching for these types. */
18043299f39fSGordon Ross MAKE_BASIC_TYPE(_char, 1)	/* ndt__char,  ndt_s_char */
18053299f39fSGordon Ross MAKE_BASIC_TYPE(_uchar, 1)	/* ndt__uchar, ndt_s_uchar */
18063299f39fSGordon Ross MAKE_BASIC_TYPE(_short, 2)	/* ndt__short, ndt_s_short */
18073299f39fSGordon Ross MAKE_BASIC_TYPE(_ushort, 2)	/* ndt__ushort, ndt_s_ushort */
18083299f39fSGordon Ross MAKE_BASIC_TYPE(_long, 4)	/* ndt__long,  ndt_s_long */
18093299f39fSGordon Ross MAKE_BASIC_TYPE(_ulong, 4)	/* ndt__ulong, ndt_s_ulong */
1810da6c28aaSamw 
18113299f39fSGordon Ross MAKE_BASIC_TYPE_BASE(_wchar, 2)	/* ndt__wchar, ndt_s_wchar */
1812da6c28aaSamw 
1813da6c28aaSamw int
18148d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size)
1815da6c28aaSamw {
18163299f39fSGordon Ross 	ndr_stream_t	*nds = ref->stream;
18178d7e4166Sjose borrego 	char 		*valp = (char *)ref->datum;
18188d7e4166Sjose borrego 	int		rc;
1819da6c28aaSamw 
18208d7e4166Sjose borrego 	switch (nds->m_op) {
1821da6c28aaSamw 	case NDR_M_OP_MARSHALL:
18228d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
18238d7e4166Sjose borrego 		    valp, nds->swap, ref);
1824da6c28aaSamw 		break;
1825da6c28aaSamw 
1826da6c28aaSamw 	case NDR_M_OP_UNMARSHALL:
18278d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
18288d7e4166Sjose borrego 		    valp, nds->swap, ref);
1829da6c28aaSamw 		break;
1830da6c28aaSamw 
1831da6c28aaSamw 	default:
1832da6c28aaSamw 		NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1833da6c28aaSamw 		return (0);
1834da6c28aaSamw 	}
1835da6c28aaSamw 
1836da6c28aaSamw 	return (rc);
1837da6c28aaSamw }
1838da6c28aaSamw 
1839da6c28aaSamw int
18408d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
1841da6c28aaSamw {
1842da6c28aaSamw 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1843da6c28aaSamw 	unsigned		size = type_under->pdu_size_fixed_part;
1844da6c28aaSamw 	char			*valp;
18458d7e4166Sjose borrego 	ndr_ref_t		myref;
1846da6c28aaSamw 	unsigned long		i;
1847da6c28aaSamw 	long			sense = 0;
1848da6c28aaSamw 	char			name[30];
1849da6c28aaSamw 
1850da6c28aaSamw 	assert(size != 0);
1851da6c28aaSamw 
1852da6c28aaSamw 	bzero(&myref, sizeof (myref));
1853da6c28aaSamw 	myref.enclosing = encl_ref;
1854da6c28aaSamw 	myref.stream = encl_ref->stream;
1855da6c28aaSamw 	myref.packed_alignment = 0;
1856da6c28aaSamw 	myref.ti = type_under;
1857da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1858da6c28aaSamw 	myref.name = name;
1859da6c28aaSamw 
1860da6c28aaSamw 	for (i = 0; i < NDR_STRING_MAX; i++) {
18613299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
1862da6c28aaSamw 		myref.pdu_offset = pdu_offset + i * size;
1863da6c28aaSamw 		valp = encl_ref->datum + i * size;
1864da6c28aaSamw 		myref.datum = valp;
1865da6c28aaSamw 
18668d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1867da6c28aaSamw 			return (0);
1868da6c28aaSamw 
1869da6c28aaSamw 		switch (size) {
1870da6c28aaSamw 		case 1:		sense = *valp; break;
1871da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1872da6c28aaSamw 		case 2:		sense = *(short *)valp; break;
1873da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1874da6c28aaSamw 		case 4:		sense = *(long *)valp; break;
1875da6c28aaSamw 		}
1876da6c28aaSamw 
1877da6c28aaSamw 		if (!sense)
1878da6c28aaSamw 			break;
1879da6c28aaSamw 	}
1880da6c28aaSamw 
1881da6c28aaSamw 	return (1);
1882da6c28aaSamw }
1883da6c28aaSamw 
1884da6c28aaSamw 
18858d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref);
18868d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = {
1887da6c28aaSamw 	1,		/* NDR version */
1888da6c28aaSamw 	2-1,		/* alignment */
1889da6c28aaSamw 	NDR_F_STRING,	/* flags */
18908d7e4166Sjose borrego 	ndr_s_wchar,	/* ndr_func */
1891da6c28aaSamw 	0,		/* pdu_size_fixed_part */
1892da6c28aaSamw 	2,		/* pdu_size_variable_part */
1893da6c28aaSamw 	0,		/* c_size_fixed_part */
1894da6c28aaSamw 	1,		/* c_size_variable_part */
1895da6c28aaSamw };
1896da6c28aaSamw 
1897da6c28aaSamw 
1898da6c28aaSamw /*
1899da6c28aaSamw  * Hand coded wchar function because all strings are transported
1900da6c28aaSamw  * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1901da6c28aaSamw  * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1902da6c28aaSamw  * convert from wide characters to multi-byte.
1903da6c28aaSamw  *
19043299f39fSGordon Ross  * The most critical thing to get right in this function is to
19053299f39fSGordon Ross  * marshall or unmarshall _exactly_ the number of elements the
19063299f39fSGordon Ross  * OtW length specifies, as saved by the caller in: strlen_is.
19073299f39fSGordon Ross  * Doing otherwise would leave us positioned at the wrong place
19083299f39fSGordon Ross  * in the data stream for whatever follows this.  Note that the
19093299f39fSGordon Ross  * string data covered by strlen_is may or may not include any
19103299f39fSGordon Ross  * null termination, but the converted string provided by the
19113299f39fSGordon Ross  * caller or returned always has a null terminator.
1912da6c28aaSamw  */
1913da6c28aaSamw int
19148d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref)
1915da6c28aaSamw {
19168d7e4166Sjose borrego 	ndr_stream_t		*nds = encl_ref->stream;
19173299f39fSGordon Ross 	char			*valp = encl_ref->datum;
19188d7e4166Sjose borrego 	ndr_ref_t		myref;
1919da6c28aaSamw 	char			name[30];
19203299f39fSGordon Ross 	ndr_wchar_t		wcs[NDR_STRING_MAX+1];
19213299f39fSGordon Ross 	size_t			i, slen, wlen;
19223299f39fSGordon Ross 
19233299f39fSGordon Ross 	/* This is enforced in ndr_outer_string() */
19243299f39fSGordon Ross 	assert(encl_ref->strlen_is <= NDR_STRING_MAX);
1925da6c28aaSamw 
19268d7e4166Sjose borrego 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1927da6c28aaSamw 		/*
1928da6c28aaSamw 		 * To avoid problems with zero length strings
1929da6c28aaSamw 		 * we can just null terminate here and be done.
1930da6c28aaSamw 		 */
1931da6c28aaSamw 		if (encl_ref->strlen_is == 0) {
1932da6c28aaSamw 			encl_ref->datum[0] = '\0';
1933da6c28aaSamw 			return (1);
1934da6c28aaSamw 		}
1935da6c28aaSamw 	}
1936da6c28aaSamw 
19373299f39fSGordon Ross 	/*
19383299f39fSGordon Ross 	 * If we're marshalling, convert the given string
19393299f39fSGordon Ross 	 * from UTF-8 into a local UCS-2 string.
19403299f39fSGordon Ross 	 */
19413299f39fSGordon Ross 	if (nds->m_op == NDR_M_OP_MARSHALL) {
19423299f39fSGordon Ross 		wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
19433299f39fSGordon Ross 		if (wlen == (size_t)-1)
19443299f39fSGordon Ross 			return (0);
19453299f39fSGordon Ross 		/*
19463299f39fSGordon Ross 		 * Add a nulls to make strlen_is.
19473299f39fSGordon Ross 		 * (always zero or one of them)
19483299f39fSGordon Ross 		 * Then null terminate at wlen,
19493299f39fSGordon Ross 		 * just for debug convenience.
19503299f39fSGordon Ross 		 */
19513299f39fSGordon Ross 		while (wlen < encl_ref->strlen_is)
19523299f39fSGordon Ross 			wcs[wlen++] = 0;
19533299f39fSGordon Ross 		wcs[wlen] = 0;
19543299f39fSGordon Ross 	}
19553299f39fSGordon Ross 
19563299f39fSGordon Ross 	/*
19573299f39fSGordon Ross 	 * Copy wire data to or from the local wc string.
19583299f39fSGordon Ross 	 * Always exactly strlen_is elements.
19593299f39fSGordon Ross 	 */
1960da6c28aaSamw 	bzero(&myref, sizeof (myref));
1961da6c28aaSamw 	myref.enclosing = encl_ref;
1962da6c28aaSamw 	myref.stream = encl_ref->stream;
1963da6c28aaSamw 	myref.packed_alignment = 0;
1964da6c28aaSamw 	myref.ti = &ndt__wchar;
1965da6c28aaSamw 	myref.inner_flags = NDR_F_NONE;
1966da6c28aaSamw 	myref.name = name;
1967da6c28aaSamw 	myref.pdu_offset = encl_ref->pdu_offset;
19683299f39fSGordon Ross 	myref.datum = (char *)wcs;
19693299f39fSGordon Ross 	wlen = encl_ref->strlen_is;
1970da6c28aaSamw 
19713299f39fSGordon Ross 	for (i = 0; i < wlen; i++) {
19723299f39fSGordon Ross 		(void) snprintf(name, sizeof (name), "[%lu]", i);
19738d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1974da6c28aaSamw 			return (0);
19753299f39fSGordon Ross 		myref.pdu_offset += sizeof (ndr_wchar_t);
19763299f39fSGordon Ross 		myref.datum	 += sizeof (ndr_wchar_t);
19773299f39fSGordon Ross 	}
1978da6c28aaSamw 
19793299f39fSGordon Ross 	/*
19803299f39fSGordon Ross 	 * If this is unmarshall, convert the local UCS-2 string
19813299f39fSGordon Ross 	 * into a UTF-8 string in the caller's buffer.  The caller
19823299f39fSGordon Ross 	 * previously determined the space required and provides a
19833299f39fSGordon Ross 	 * buffer of sufficient size.
19843299f39fSGordon Ross 	 */
19853299f39fSGordon Ross 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
19863299f39fSGordon Ross 		wcs[wlen] = 0;
1987*d1855c81SGordon Ross 		slen = encl_ref->size_is * NDR_MB_CHAR_MAX;
1988*d1855c81SGordon Ross 		slen = ndr__wcstombs(valp, wcs, slen);
19893299f39fSGordon Ross 		if (slen == (size_t)-1)
19903299f39fSGordon Ross 			return (0);
19913299f39fSGordon Ross 		valp[slen] = '\0';
1992da6c28aaSamw 	}
1993da6c28aaSamw 
1994da6c28aaSamw 	return (1);
1995da6c28aaSamw }
199655bf511dSas 
199755bf511dSas /*
199855bf511dSas  * Converts a multibyte character string to a little-endian, wide-char
199955bf511dSas  * string.  No more than nwchars wide characters are stored.
200055bf511dSas  * A terminating null wide character is appended if there is room.
200155bf511dSas  *
200255bf511dSas  * Returns the number of wide characters converted, not counting
200355bf511dSas  * any terminating null wide character.  Returns -1 if an invalid
200455bf511dSas  * multibyte character is encountered.
200555bf511dSas  */
20063299f39fSGordon Ross /* ARGSUSED */
200755bf511dSas size_t
20083299f39fSGordon Ross ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
200955bf511dSas     size_t nwchars)
201055bf511dSas {
20113299f39fSGordon Ross 	size_t len;
201255bf511dSas 
201355bf511dSas #ifdef _BIG_ENDIAN
20143299f39fSGordon Ross 	if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
20153299f39fSGordon Ross 		/* Make WC string in LE order. */
20163299f39fSGordon Ross 		len = ndr__mbstowcs_le(wcs, mbs, nwchars);
20173299f39fSGordon Ross 	} else
201855bf511dSas #endif
20193299f39fSGordon Ross 		len = ndr__mbstowcs(wcs, mbs, nwchars);
202055bf511dSas 
20213299f39fSGordon Ross 	return (len);
202255bf511dSas }
2023