xref: /titanic_51/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c (revision 33f5ff17089e3a43e6e730bf80384c233123dbd9)
1dc20a302Sas200622 /*
2dc20a302Sas200622  * CDDL HEADER START
3dc20a302Sas200622  *
4dc20a302Sas200622  * The contents of this file are subject to the terms of the
5dc20a302Sas200622  * Common Development and Distribution License (the "License").
6dc20a302Sas200622  * You may not use this file except in compliance with the License.
7dc20a302Sas200622  *
8dc20a302Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dc20a302Sas200622  * or http://www.opensolaris.org/os/licensing.
10dc20a302Sas200622  * See the License for the specific language governing permissions
11dc20a302Sas200622  * and limitations under the License.
12dc20a302Sas200622  *
13dc20a302Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
14dc20a302Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dc20a302Sas200622  * If applicable, add the following below this CDDL HEADER, with the
16dc20a302Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
17dc20a302Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
18dc20a302Sas200622  *
19dc20a302Sas200622  * CDDL HEADER END
20dc20a302Sas200622  */
21dc20a302Sas200622 /*
22f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23dc20a302Sas200622  * Use is subject to license terms.
24*33f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
25dc20a302Sas200622  */
26dc20a302Sas200622 
27dc20a302Sas200622 /*
28dc20a302Sas200622  * Network Data Representation (NDR) is a compatible subset of the DCE RPC
29dc20a302Sas200622  * and MSRPC NDR.  NDR is used to move parameters consisting of
30dc20a302Sas200622  * complicated trees of data constructs between an RPC client and server.
31dc20a302Sas200622  */
32dc20a302Sas200622 
33dc20a302Sas200622 #include <sys/byteorder.h>
34dc20a302Sas200622 #include <strings.h>
35dc20a302Sas200622 #include <assert.h>
36dc20a302Sas200622 #include <string.h>
37dc20a302Sas200622 #include <stdlib.h>
38dc20a302Sas200622 
39dc20a302Sas200622 #include <smbsrv/libsmb.h>
40dc20a302Sas200622 #include <smbsrv/string.h>
418d7e4166Sjose borrego #include <smbsrv/libmlrpc.h>
42dc20a302Sas200622 
43f96bd5c8SAlan Wright #define	NDR_STRING_MAX		4096
44dc20a302Sas200622 
45dc20a302Sas200622 #define	NDR_IS_UNION(T)	\
46dc20a302Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
47dc20a302Sas200622 #define	NDR_IS_STRING(T)	\
48dc20a302Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
49dc20a302Sas200622 
508d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar;
51dc20a302Sas200622 
52dc20a302Sas200622 /*
53dc20a302Sas200622  * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
54dc20a302Sas200622  *
55dc20a302Sas200622  * Each parameter (call arguments and return values) is a TOP-MOST item.
56dc20a302Sas200622  * A TOP-MOST item consists of one or more OUTER items.  An OUTER item
57dc20a302Sas200622  * consists of one or more INNER items.  There are important differences
58dc20a302Sas200622  * between each kind, which, primarily, have to do with the allocation
59dc20a302Sas200622  * of memory to contain data structures and the order of processing.
60dc20a302Sas200622  *
61dc20a302Sas200622  * This is most easily demonstrated with a short example.
62dc20a302Sas200622  * Consider these structures:
63dc20a302Sas200622  *
64dc20a302Sas200622  *	struct top_param {
65dc20a302Sas200622  *		long		level;
66dc20a302Sas200622  *		struct list *	head;
67dc20a302Sas200622  *		long		count;
68dc20a302Sas200622  *	};
69dc20a302Sas200622  *
70dc20a302Sas200622  *	struct list {
71dc20a302Sas200622  *		struct list *	next;
72dc20a302Sas200622  *		char *		str; // a string
73dc20a302Sas200622  *	};
74dc20a302Sas200622  *
75dc20a302Sas200622  * Now, consider an instance tree like this:
76dc20a302Sas200622  *
77dc20a302Sas200622  *	+---------+       +-------+       +-------+
78dc20a302Sas200622  *	|top_param|  +--->|list #1|  +--->|list #2|
79dc20a302Sas200622  *	+---------+  |    +-------+  |    +-------+
80dc20a302Sas200622  *	| level   |  |    | next ----+    | next --->(NULL)
81dc20a302Sas200622  *	| head   ----+    | str  -->"foo" | str  -->"bar"
82dc20a302Sas200622  *	| count   |       | flag  |       | flag  |
83dc20a302Sas200622  *	+---------+       +-------+       +-------+
84dc20a302Sas200622  *
85dc20a302Sas200622  * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
86dc20a302Sas200622  * The vertical bars (|) indicate OUTER construct boundaries.
87dc20a302Sas200622  *
88dc20a302Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
89dc20a302Sas200622  *   |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
90dc20a302Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
91dc20a302Sas200622  *   level |<----------------------- head -------------------------->|count
92dc20a302Sas200622  *   TOP    TOP                                                       TOP
93dc20a302Sas200622  *
94dc20a302Sas200622  * Here's what to notice:
95dc20a302Sas200622  *
96dc20a302Sas200622  * - The members of the TOP-MOST construct are scattered through the Stub
97dc20a302Sas200622  *   Data in the order they occur.  This example shows a TOP-MOST construct
98dc20a302Sas200622  *   consisting of atomic types (pointers and integers).  A construct
99dc20a302Sas200622  *   (struct) within the TOP-MOST construct would be contiguous and not
100dc20a302Sas200622  *   scattered.
101dc20a302Sas200622  *
102dc20a302Sas200622  * - The members of OUTER constructs are contiguous, which allows for
103dc20a302Sas200622  *   non-copied relocated (fixed-up) data structures at the packet's
104dc20a302Sas200622  *   destination.  We don't do fix-ups here.  The pointers within the
105dc20a302Sas200622  *   OUTER constructs are processed depth-first in the order that they
106dc20a302Sas200622  *   occur.  If they were processed breadth first, the sequence would
107dc20a302Sas200622  *   be #1,"foo",#2,"bar".  This is tricky because OUTER constructs may
108dc20a302Sas200622  *   be variable length, and pointers are often encountered before the
109dc20a302Sas200622  *   size(s) is known.
110dc20a302Sas200622  *
111dc20a302Sas200622  * - The INNER constructs are simply the members of an OUTER construct.
112dc20a302Sas200622  *
113dc20a302Sas200622  * For comparison, consider how ONC RPC would handle the same tree of
114dc20a302Sas200622  * data.  ONC requires very little buffering, while DCE requires enough
115dc20a302Sas200622  * buffer space for the entire message.  ONC does atom-by-atom depth-first
116dc20a302Sas200622  * (de)serialization and copy, while DCE allows for constructs to be
117dc20a302Sas200622  * "fixed-up" (relocated) in place at the destination.  The packet data
118dc20a302Sas200622  * for the same tree processed by ONC RPC would look like this:
119dc20a302Sas200622  *
120dc20a302Sas200622  *   +---------------------------------------------------------------------+
121dc20a302Sas200622  *   |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
122dc20a302Sas200622  *   +---------------------------------------------------------------------+
123dc20a302Sas200622  *   TOP    #1      #2      #2     bar   #2      #1     foo   #1      TOP
124dc20a302Sas200622  *
125dc20a302Sas200622  * More details about each TOP-MOST, OUTER, and INNER constructs appear
126dc20a302Sas200622  * throughout this source file near where such constructs are processed.
127dc20a302Sas200622  *
128dc20a302Sas200622  * NDR_REFERENCE
129dc20a302Sas200622  *
1308d7e4166Sjose borrego  * The primary object for NDR is the ndr_ref_t.
131dc20a302Sas200622  *
1328d7e4166Sjose borrego  * An ndr reference indicates the local datum (i.e. native "C" data
133dc20a302Sas200622  * format), and the element within the Stub Data (contained within the
1348d7e4166Sjose borrego  * RPC PDU (protocol data unit).  An ndr reference also indicates,
135dc20a302Sas200622  * largely as a debugging aid, something about the type of the
136dc20a302Sas200622  * 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
139dc20a302Sas200622  * order of the call graph.
140dc20a302Sas200622  *
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
143dc20a302Sas200622  * where in the Stub Data the value is to be stored/retrieved.
144dc20a302Sas200622  *
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
148dc20a302Sas200622  * indicates the arm of a union to use.
149dc20a302Sas200622  *
150dc20a302Sas200622  * QUEUE OF OUTER REFERENCES
151dc20a302Sas200622  *
152dc20a302Sas200622  * Some OUTER constructs are variable size.  Sometimes (often) we don't
153dc20a302Sas200622  * know the size of the OUTER construct until after pointers have been
154dc20a302Sas200622  * encountered. Hence, we can not begin processing the referent of the
155dc20a302Sas200622  * pointer until after the referring OUTER construct is completely
156dc20a302Sas200622  * processed, i.e. we don't know where to find/put the referent in the
157dc20a302Sas200622  * Stub Data until we know the size of all its predecessors.
158dc20a302Sas200622  *
159dc20a302Sas200622  * 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.
163dc20a302Sas200622  *
164dc20a302Sas200622  * Refer to the example above as we illustrate the queue here.  In these
165dc20a302Sas200622  * illustrations, the queue entries are not the data structures themselves.
1668d7e4166Sjose borrego  * Rather, they are ndr-reference entries which **refer** to the data
167dc20a302Sas200622  * structures in both the PDU and local memory.
168dc20a302Sas200622  *
169dc20a302Sas200622  * During some point in the processing, the queue looks like this:
170dc20a302Sas200622  *
171dc20a302Sas200622  *   outer_current -------v
172dc20a302Sas200622  *   outer_queue_head --> list#1 --0
173dc20a302Sas200622  *   outer_queue_tailp ---------&
174dc20a302Sas200622  *
175dc20a302Sas200622  * When the pointer #1.next is encountered, and entry is added to the
176dc20a302Sas200622  * queue,
177dc20a302Sas200622  *
178dc20a302Sas200622  *   outer_current -------v
179dc20a302Sas200622  *   outer_queue_head --> list#1 --> list#2 --0
180dc20a302Sas200622  *   outer_queue_tailp --------------------&
181dc20a302Sas200622  *
182dc20a302Sas200622  * and the members of #1 continue to be processed, which encounters
183dc20a302Sas200622  * #1.str:
184dc20a302Sas200622  *
185dc20a302Sas200622  *   outer_current -------v
186dc20a302Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
187dc20a302Sas200622  *   outer_queue_tailp ------------------------------&
188dc20a302Sas200622  *
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:
191dc20a302Sas200622  *
192dc20a302Sas200622  *   outer_current ------------------v
193dc20a302Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
194dc20a302Sas200622  *   outer_queue_tailp --------------------&
195dc20a302Sas200622  *
196dc20a302Sas200622  * Space for list#2 is allocated, either in the Stub Data or of local
197dc20a302Sas200622  * memory.  When #2.next is encountered, it is found to be the null
198dc20a302Sas200622  * pointer and no reference is added to the queue.  When #2.str is
199dc20a302Sas200622  * encountered, it is found to be valid, and a reference is added:
200dc20a302Sas200622  *
201dc20a302Sas200622  *   outer_current ------------------v
202dc20a302Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
203dc20a302Sas200622  *   outer_queue_tailp ------------------------------&
204dc20a302Sas200622  *
205dc20a302Sas200622  * Processing continues in a similar fashion with the string "bar",
206dc20a302Sas200622  * which is variable-length.  At this point, memory for "bar" may be
207dc20a302Sas200622  * malloc()ed during NDR_M_OP_UNMARSHALL:
208dc20a302Sas200622  *
209dc20a302Sas200622  *   outer_current -----------------------------v
210dc20a302Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
211dc20a302Sas200622  *   outer_queue_tailp ------------------------------&
212dc20a302Sas200622  *
213dc20a302Sas200622  * And finishes on string "foo".  Notice that because "bar" is a
214dc20a302Sas200622  * variable length string, and we don't know the PDU offset for "foo"
215dc20a302Sas200622  * until we reach this point.
216dc20a302Sas200622  *
217dc20a302Sas200622  * When the queue is drained (current->next==0), processing continues
218dc20a302Sas200622  * with the next TOP-MOST member.
219dc20a302Sas200622  *
220dc20a302Sas200622  * The queue of OUTER constructs manages the variable-length semantics
221dc20a302Sas200622  * of OUTER constructs and satisfies the depth-first requirement.
222dc20a302Sas200622  * We allow the queue to linger until the entire TOP-MOST structure is
223dc20a302Sas200622  * processed as an aid to debugging.
224dc20a302Sas200622  */
225dc20a302Sas200622 
2268d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
2278d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *);
228dc20a302Sas200622 
229dc20a302Sas200622 /*
230dc20a302Sas200622  * TOP-MOST ELEMENTS
231dc20a302Sas200622  *
232dc20a302Sas200622  * This is fundamentally the first OUTER construct of the parameter,
233dc20a302Sas200622  * possibly followed by more OUTER constructs due to pointers.  The
234dc20a302Sas200622  * datum (local memory) for TOP-MOST constructs (structs) is allocated
235dc20a302Sas200622  * by the caller of NDR.
236dc20a302Sas200622  *
237dc20a302Sas200622  * After the element is transferred, the outer_queue is drained.
238dc20a302Sas200622  *
239dc20a302Sas200622  * All we have to do is add an entry to the outer_queue for this
240dc20a302Sas200622  * top-most member, and commence the outer_queue processing.
241dc20a302Sas200622  */
242dc20a302Sas200622 int
2438d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
244dc20a302Sas200622 {
2458d7e4166Sjose borrego 	ndr_ref_t	myref;
246dc20a302Sas200622 
247dc20a302Sas200622 	bzero(&myref, sizeof (myref));
2488d7e4166Sjose borrego 	myref.stream = nds;
249dc20a302Sas200622 	myref.datum = datum;
250dc20a302Sas200622 	myref.name = "PROCESS";
251dc20a302Sas200622 	myref.ti = ti;
252dc20a302Sas200622 
2538d7e4166Sjose borrego 	return (ndr_topmost(&myref));
254dc20a302Sas200622 }
255dc20a302Sas200622 
256dc20a302Sas200622 int
2578d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
258dc20a302Sas200622 {
2598d7e4166Sjose borrego 	ndr_ref_t	myref;
260dc20a302Sas200622 
261dc20a302Sas200622 	bzero(&myref, sizeof (myref));
2628d7e4166Sjose borrego 	myref.stream = nds;
263dc20a302Sas200622 	myref.datum = datum;
264dc20a302Sas200622 	myref.name = "OPERATION";
265dc20a302Sas200622 	myref.ti = ti;
266dc20a302Sas200622 	myref.inner_flags = NDR_F_SWITCH_IS;
267dc20a302Sas200622 	myref.switch_is = opnum;
268dc20a302Sas200622 
269dc20a302Sas200622 	if (ti->type_flags != NDR_F_INTERFACE) {
270dc20a302Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
271dc20a302Sas200622 		return (0);
272dc20a302Sas200622 	}
273dc20a302Sas200622 
274dc20a302Sas200622 	return ((*ti->ndr_func)(&myref));
275dc20a302Sas200622 }
276dc20a302Sas200622 
277dc20a302Sas200622 int
2788d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref)
279dc20a302Sas200622 {
2808d7e4166Sjose borrego 	ndr_typeinfo_t *ti = params_ref->ti;
281dc20a302Sas200622 
282dc20a302Sas200622 	if (ti->type_flags == NDR_F_OPERATION)
283dc20a302Sas200622 		return (*ti->ndr_func) (params_ref);
284dc20a302Sas200622 	else
2858d7e4166Sjose borrego 		return (ndr_topmost(params_ref));
286dc20a302Sas200622 }
287dc20a302Sas200622 
288dc20a302Sas200622 int
2898d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref)
290dc20a302Sas200622 {
2918d7e4166Sjose borrego 	ndr_stream_t *nds;
2928d7e4166Sjose borrego 	ndr_typeinfo_t *ti;
2938d7e4166Sjose borrego 	ndr_ref_t *outer_ref = 0;
294dc20a302Sas200622 	int	is_varlen;
295dc20a302Sas200622 	int	is_string;
296dc20a302Sas200622 	int	error;
297dc20a302Sas200622 	int	rc;
298dc20a302Sas200622 	unsigned n_fixed;
299dc20a302Sas200622 	int	params;
300dc20a302Sas200622 
301dc20a302Sas200622 	assert(top_ref);
302dc20a302Sas200622 	assert(top_ref->stream);
303dc20a302Sas200622 	assert(top_ref->ti);
304dc20a302Sas200622 
3058d7e4166Sjose borrego 	nds = top_ref->stream;
306dc20a302Sas200622 	ti = top_ref->ti;
307dc20a302Sas200622 
308dc20a302Sas200622 	is_varlen = ti->pdu_size_variable_part;
309dc20a302Sas200622 	is_string = NDR_IS_STRING(ti);
310dc20a302Sas200622 
3118d7e4166Sjose borrego 	assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
3128d7e4166Sjose borrego 	assert(!nds->outer_current);
313dc20a302Sas200622 
314dc20a302Sas200622 	params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
315dc20a302Sas200622 
316dc20a302Sas200622 	switch (params) {
317dc20a302Sas200622 	case NDR_F_NONE:
318dc20a302Sas200622 	case NDR_F_SWITCH_IS:
319dc20a302Sas200622 		if (is_string || is_varlen) {
320dc20a302Sas200622 			error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
321dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, error);
322dc20a302Sas200622 			return (0);
323dc20a302Sas200622 		}
324dc20a302Sas200622 		n_fixed = ti->pdu_size_fixed_part;
325dc20a302Sas200622 		break;
326dc20a302Sas200622 
327dc20a302Sas200622 	case NDR_F_SIZE_IS:
328dc20a302Sas200622 		error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
329dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, error);
330dc20a302Sas200622 		return (0);
331dc20a302Sas200622 
332dc20a302Sas200622 	case NDR_F_DIMENSION_IS:
333dc20a302Sas200622 		if (is_varlen) {
334dc20a302Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
335dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, error);
336dc20a302Sas200622 			return (0);
337dc20a302Sas200622 		}
338dc20a302Sas200622 		n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
339dc20a302Sas200622 		break;
340dc20a302Sas200622 
341dc20a302Sas200622 	case NDR_F_IS_POINTER:
342dc20a302Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
343dc20a302Sas200622 		n_fixed = 4;
344dc20a302Sas200622 		break;
345dc20a302Sas200622 
346dc20a302Sas200622 	case NDR_F_IS_REFERENCE:
347dc20a302Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
348dc20a302Sas200622 		n_fixed = 0;
349dc20a302Sas200622 		break;
350dc20a302Sas200622 
351dc20a302Sas200622 	default:
352dc20a302Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
353dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, error);
354dc20a302Sas200622 		return (0);
355dc20a302Sas200622 	}
356dc20a302Sas200622 
3578d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(top_ref);
358dc20a302Sas200622 	if (!outer_ref)
359dc20a302Sas200622 		return (0);	/* error already set */
360dc20a302Sas200622 
361dc20a302Sas200622 	/*
362dc20a302Sas200622 	 * 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
365dc20a302Sas200622 	 * the construct, and we already have the memory.
366dc20a302Sas200622 	 */
367dc20a302Sas200622 
368dc20a302Sas200622 	/* move the flags, etc, around again, undoes enter_outer_queue() */
369dc20a302Sas200622 	outer_ref->inner_flags = top_ref->inner_flags;
370dc20a302Sas200622 	outer_ref->outer_flags = 0;
371dc20a302Sas200622 	outer_ref->datum = top_ref->datum;
372dc20a302Sas200622 
373dc20a302Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
3748d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
375dc20a302Sas200622 		return (0);		/* error already set */
376dc20a302Sas200622 
377dc20a302Sas200622 	/* Regardless of what it is, this is where it starts */
3788d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
379dc20a302Sas200622 
3808d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_fixed);
381dc20a302Sas200622 	if (!rc)
382dc20a302Sas200622 		return (0);		/* error already set */
383dc20a302Sas200622 
384dc20a302Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
385dc20a302Sas200622 
386dc20a302Sas200622 	/* 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;
390dc20a302Sas200622 
391dc20a302Sas200622 	/* do the topmost member */
3928d7e4166Sjose borrego 	rc = ndr_inner(outer_ref);
393dc20a302Sas200622 	if (!rc)
394dc20a302Sas200622 		return (0);		/* error already set */
395dc20a302Sas200622 
3968d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
397dc20a302Sas200622 
398dc20a302Sas200622 	/* 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));
401dc20a302Sas200622 }
402dc20a302Sas200622 
4038d7e4166Sjose borrego static ndr_ref_t *
4048d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref)
405dc20a302Sas200622 {
4068d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
4078d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
408dc20a302Sas200622 
409dc20a302Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
4108d7e4166Sjose borrego 	outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
411dc20a302Sas200622 	if (!outer_ref) {
412dc20a302Sas200622 		NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
413dc20a302Sas200622 		return (0);
414dc20a302Sas200622 	}
415dc20a302Sas200622 
416dc20a302Sas200622 	*outer_ref = *arg_ref;
417dc20a302Sas200622 
418dc20a302Sas200622 	/* move advice in inner_flags to outer_flags */
419dc20a302Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
420dc20a302Sas200622 	outer_ref->inner_flags = 0;
4218d7e4166Sjose borrego 	outer_ref->enclosing = nds->outer_current;
422dc20a302Sas200622 	outer_ref->backptr = 0;
423dc20a302Sas200622 	outer_ref->datum = 0;
424dc20a302Sas200622 
4258d7e4166Sjose borrego 	assert(nds->outer_queue_tailp);
426dc20a302Sas200622 
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;
430dc20a302Sas200622 	return (outer_ref);
431dc20a302Sas200622 }
432dc20a302Sas200622 
433dc20a302Sas200622 int
4348d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds)
435dc20a302Sas200622 {
4368d7e4166Sjose borrego 	while (nds->outer_current) {
4378d7e4166Sjose borrego 		nds->outer_queue_tailp = &nds->outer_current->next;
438dc20a302Sas200622 
4398d7e4166Sjose borrego 		if (!ndr_outer(nds->outer_current))
440dc20a302Sas200622 			return (0);
441dc20a302Sas200622 
4428d7e4166Sjose borrego 		nds->outer_current = nds->outer_current->next;
443dc20a302Sas200622 	}
444dc20a302Sas200622 
445dc20a302Sas200622 	return (1);
446dc20a302Sas200622 }
447dc20a302Sas200622 
448dc20a302Sas200622 /*
449dc20a302Sas200622  * OUTER CONSTRUCTS
450dc20a302Sas200622  *
451dc20a302Sas200622  * OUTER constructs are where the real work is, which stems from the
452dc20a302Sas200622  * variable-length potential.
453dc20a302Sas200622  *
454dc20a302Sas200622  * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
455dc20a302Sas200622  *
456dc20a302Sas200622  * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
457dc20a302Sas200622  * VARYING, and VARYING/CONFORMANT.
458dc20a302Sas200622  *
459dc20a302Sas200622  * What makes this so tough is that the variable-length array may be well
460dc20a302Sas200622  * encapsulated within the outer construct.  Further, because DCE(MS)/RPC
461dc20a302Sas200622  * tries to keep the constructs contiguous in the data stream, the sizing
462dc20a302Sas200622  * information precedes the entire OUTER construct.  The sizing information
463dc20a302Sas200622  * must be used at the appropriate time, which can be after many, many,
464dc20a302Sas200622  * many fixed-length elements.  During IDL type analysis, we know in
465dc20a302Sas200622  * advance constructs that encapsulate variable-length constructs.  So,
466dc20a302Sas200622  * we know when we have a sizing header and when we don't.  The actual
467dc20a302Sas200622  * semantics of the header are largely deferred.
468dc20a302Sas200622  *
469dc20a302Sas200622  * Currently, VARYING constructs are not implemented but they are described
470dc20a302Sas200622  * here in case they have to be implemented in the future.  Similarly,
471dc20a302Sas200622  * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
472dc20a302Sas200622  * not implemented.  Only one-dimensional, variable-length arrays are
473dc20a302Sas200622  * supported.
474dc20a302Sas200622  *
475dc20a302Sas200622  * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
476dc20a302Sas200622  *
477dc20a302Sas200622  * All variable-length values are arrays.  These arrays may be embedded
478dc20a302Sas200622  * well within another construct.  However, a variable-length construct
479dc20a302Sas200622  * may ONLY appear as the last member of an enclosing construct.  Example:
480dc20a302Sas200622  *
481dc20a302Sas200622  *	struct credentials {
482dc20a302Sas200622  *		ulong	uid, gid;
483dc20a302Sas200622  *		ulong	n_gids;
484dc20a302Sas200622  *	    [size_is(n_gids)]
485dc20a302Sas200622  *		ulong	gids[*];    // variable-length.
486dc20a302Sas200622  *	};
487dc20a302Sas200622  *
488dc20a302Sas200622  * CONFORMANT constructs have a dynamic size in local memory and in the
489dc20a302Sas200622  * PDU.  The CONFORMANT quality is indicated by the [size_is()] advice.
490dc20a302Sas200622  * CONFORMANT constructs have the following header:
491dc20a302Sas200622  *
492dc20a302Sas200622  *	struct conformant_header {
493dc20a302Sas200622  *		ulong		size_is;
494dc20a302Sas200622  *	};
495dc20a302Sas200622  *
496dc20a302Sas200622  * (Multi-dimensional CONFORMANT arrays have a similar header for each
497dc20a302Sas200622  * dimension - not implemented).
498dc20a302Sas200622  *
499dc20a302Sas200622  * Example CONFORMANT construct:
500dc20a302Sas200622  *
501dc20a302Sas200622  *	struct user {
502dc20a302Sas200622  *		char *			name;
503dc20a302Sas200622  *		struct credentials	cred;	// see above
504dc20a302Sas200622  *	};
505dc20a302Sas200622  *
506dc20a302Sas200622  * Consider the data tree:
507dc20a302Sas200622  *
508dc20a302Sas200622  *    +--------+
509dc20a302Sas200622  *    |  user  |
510dc20a302Sas200622  *    +--------+
511dc20a302Sas200622  *    | name  ----> "fred" (the string is a different OUTER)
512dc20a302Sas200622  *    | uid    |
513dc20a302Sas200622  *    | gid    |
514dc20a302Sas200622  *    | n_gids |    for example, 3
515dc20a302Sas200622  *    | gids[0]|
516dc20a302Sas200622  *    | gids[1]|
517dc20a302Sas200622  *    | gids[2]|
518dc20a302Sas200622  *    +--------+
519dc20a302Sas200622  *
520dc20a302Sas200622  * The OUTER construct in the Stub Data would be:
521dc20a302Sas200622  *
522dc20a302Sas200622  *    +---+---------+---------------------------------------------+
523dc20a302Sas200622  *    |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
524dc20a302Sas200622  *    +---+---------+---------------------------------------------+
525dc20a302Sas200622  *         szing hdr|user |<-------------- user.cred ------------>|
526dc20a302Sas200622  *                  |<--- fixed-size ---->|<----- conformant ---->|
527dc20a302Sas200622  *
528dc20a302Sas200622  * The ndr_typeinfo for struct user will have:
529dc20a302Sas200622  *	pdu_fixed_size_part = 16	four long words (name uid gid n_gids)
530dc20a302Sas200622  *	pdu_variable_size_part = 4	per element, sizeof gids[0]
531dc20a302Sas200622  *
532dc20a302Sas200622  * VARYING CONSTRUCTS -- NOT IMPLEMENTED
533dc20a302Sas200622  *
534dc20a302Sas200622  * VARYING constructs have the following header:
535dc20a302Sas200622  *
536dc20a302Sas200622  *	struct varying_header {
537dc20a302Sas200622  *		ulong		first_is;
538dc20a302Sas200622  *		ulong		length_is;
539dc20a302Sas200622  *	};
540dc20a302Sas200622  *
541dc20a302Sas200622  * This indicates which interval of an array is significant.
542dc20a302Sas200622  * Non-intersecting elements of the array are undefined and usually
543dc20a302Sas200622  * zero-filled.  The first_is parameter for C arrays is always 0 for
544dc20a302Sas200622  * the first element.
545dc20a302Sas200622  *
546dc20a302Sas200622  * N.B. Constructs may contain one CONFORMANT element, which is always
547dc20a302Sas200622  * last, but may contain many VARYING elements, which can be anywhere.
548dc20a302Sas200622  *
549dc20a302Sas200622  * VARYING CONFORMANT constructs have the sizing headers arranged like
550dc20a302Sas200622  * this:
551dc20a302Sas200622  *
552dc20a302Sas200622  *	struct conformant_header	all_conformant[N_CONFORMANT_DIM];
553dc20a302Sas200622  *	struct varying_header		all_varying[N_VARYING_ELEMS_AND_DIMS];
554dc20a302Sas200622  *
555dc20a302Sas200622  * The sizing header is immediately followed by the values for the
556dc20a302Sas200622  * construct.  Again, we don't support more than one dimension and
557dc20a302Sas200622  * we don't support VARYING constructs at this time.
558dc20a302Sas200622  *
559dc20a302Sas200622  * A good example of a VARYING/CONFORMANT data structure is the UNIX
560dc20a302Sas200622  * directory entry:
561dc20a302Sas200622  *
562dc20a302Sas200622  *	struct dirent {
563dc20a302Sas200622  *		ushort		reclen;
564dc20a302Sas200622  *		ushort		namlen;
565dc20a302Sas200622  *		ulong		inum;
566dc20a302Sas200622  *	    [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
567dc20a302Sas200622  *		uchar		name[*];
568dc20a302Sas200622  *	};
569dc20a302Sas200622  *
570dc20a302Sas200622  *
571dc20a302Sas200622  * STRINGS ARE A SPECIAL CASE
572dc20a302Sas200622  *
573dc20a302Sas200622  * Strings are handled specially.  MS/RPC uses VARYING/CONFORMANT structures
574dc20a302Sas200622  * for strings.  This is a simple one-dimensional variable-length array,
575dc20a302Sas200622  * typically with its last element all zeroes.  We handle strings with the
576dc20a302Sas200622  * header:
577dc20a302Sas200622  *
578dc20a302Sas200622  *	struct string_header {
579dc20a302Sas200622  *		ulong		size_is;
580dc20a302Sas200622  *		ulong		first_is;	// always 0
581dc20a302Sas200622  *		ulong		length_is;	// always same as size_is
582dc20a302Sas200622  *	};
583dc20a302Sas200622  *
584dc20a302Sas200622  * If general support for VARYING and VARYING/CONFORMANT mechanisms is
585dc20a302Sas200622  * implemented, we probably won't need the strings special case.
586dc20a302Sas200622  */
587dc20a302Sas200622 int
5888d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref)
589dc20a302Sas200622 {
5908d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
5918d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
592dc20a302Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
593dc20a302Sas200622 	int	is_union = NDR_IS_UNION(ti);
594dc20a302Sas200622 	int	is_string = NDR_IS_STRING(ti);
595dc20a302Sas200622 	int	error = NDR_ERR_OUTER_PARAMS_BAD;
596dc20a302Sas200622 	int	params;
597dc20a302Sas200622 
598dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
599dc20a302Sas200622 
600dc20a302Sas200622 	NDR_TATTLE(outer_ref, "--OUTER--");
601dc20a302Sas200622 
602dc20a302Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
6038d7e4166Sjose borrego 	if (!ndr_outer_align(outer_ref))
604dc20a302Sas200622 		return (0);		/* error already set */
605dc20a302Sas200622 
606dc20a302Sas200622 	/* Regardless of what it is, this is where it starts */
6078d7e4166Sjose borrego 	outer_ref->pdu_offset = nds->pdu_scan_offset;
608dc20a302Sas200622 
609dc20a302Sas200622 	if (is_union) {
610dc20a302Sas200622 		error = NDR_ERR_OUTER_UNION_ILLEGAL;
611dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, error);
612dc20a302Sas200622 		return (0);
613dc20a302Sas200622 	}
614dc20a302Sas200622 
615dc20a302Sas200622 	switch (params) {
616dc20a302Sas200622 	case NDR_F_NONE:
617dc20a302Sas200622 		if (is_string)
6188d7e4166Sjose borrego 			return (ndr_outer_string(outer_ref));
619dc20a302Sas200622 		if (is_varlen)
6208d7e4166Sjose borrego 			return (ndr_outer_conformant_construct(outer_ref));
621dc20a302Sas200622 
6228d7e4166Sjose borrego 		return (ndr_outer_fixed(outer_ref));
623dc20a302Sas200622 
624dc20a302Sas200622 	case NDR_F_SIZE_IS:
625dc20a302Sas200622 	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:
628dc20a302Sas200622 		if (is_varlen) {
629dc20a302Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
630dc20a302Sas200622 			break;
631dc20a302Sas200622 		}
632dc20a302Sas200622 
633f96bd5c8SAlan Wright 		if (params & NDR_F_SIZE_IS)
6348d7e4166Sjose borrego 			return (ndr_outer_conformant_array(outer_ref));
635dc20a302Sas200622 		else
6368d7e4166Sjose borrego 			return (ndr_outer_fixed_array(outer_ref));
637dc20a302Sas200622 
638dc20a302Sas200622 	default:
639dc20a302Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
640dc20a302Sas200622 		break;
641dc20a302Sas200622 	}
642dc20a302Sas200622 
643dc20a302Sas200622 	/*
644dc20a302Sas200622 	 * If we get here, something is wrong. Most likely,
645dc20a302Sas200622 	 * the params flags do not match.
646dc20a302Sas200622 	 */
647dc20a302Sas200622 	NDR_SET_ERROR(outer_ref, error);
648dc20a302Sas200622 	return (0);
649dc20a302Sas200622 }
650dc20a302Sas200622 
651dc20a302Sas200622 int
6528d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref)
653dc20a302Sas200622 {
6548d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
6558d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
6568d7e4166Sjose borrego 	ndr_ref_t	myref;
657dc20a302Sas200622 	char 		*valp = NULL;
658dc20a302Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
659dc20a302Sas200622 	int		is_union = NDR_IS_UNION(ti);
660dc20a302Sas200622 	int		is_string = NDR_IS_STRING(ti);
661dc20a302Sas200622 	int		rc;
662dc20a302Sas200622 	unsigned	n_hdr;
663dc20a302Sas200622 	unsigned	n_fixed;
664dc20a302Sas200622 	unsigned	n_variable;
665dc20a302Sas200622 	unsigned	n_alloc;
666dc20a302Sas200622 	unsigned	n_pdu_total;
667dc20a302Sas200622 	int		params;
668dc20a302Sas200622 
669dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
670dc20a302Sas200622 
671dc20a302Sas200622 	assert(!is_varlen && !is_string && !is_union);
672dc20a302Sas200622 	assert(params == NDR_F_NONE);
673dc20a302Sas200622 
674dc20a302Sas200622 	/* no header for this */
675dc20a302Sas200622 	n_hdr = 0;
676dc20a302Sas200622 
677dc20a302Sas200622 	/* fixed part -- exactly one of these */
678dc20a302Sas200622 	n_fixed = ti->pdu_size_fixed_part;
679dc20a302Sas200622 	assert(n_fixed > 0);
680dc20a302Sas200622 
681dc20a302Sas200622 	/* variable part -- exactly none of these */
682dc20a302Sas200622 	n_variable = 0;
683dc20a302Sas200622 
684dc20a302Sas200622 	/* sum them up to determine the PDU space required */
685dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
686dc20a302Sas200622 
687dc20a302Sas200622 	/* similar sum to determine how much local memory is required */
688dc20a302Sas200622 	n_alloc = n_fixed + n_variable;
689dc20a302Sas200622 
6908d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
691dc20a302Sas200622 	if (!rc)
692dc20a302Sas200622 		return (rc);		/* error already set */
693dc20a302Sas200622 
6948d7e4166Sjose borrego 	switch (nds->m_op) {
695dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
696dc20a302Sas200622 		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)
702dc20a302Sas200622 			assert(valp == *outer_ref->backptr);
703dc20a302Sas200622 		break;
704dc20a302Sas200622 
705dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
7068d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
707dc20a302Sas200622 		if (!valp) {
708dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
709dc20a302Sas200622 			return (0);
710dc20a302Sas200622 		}
711dc20a302Sas200622 		if (outer_ref->backptr)
712dc20a302Sas200622 			*outer_ref->backptr = valp;
713dc20a302Sas200622 		outer_ref->datum = valp;
714dc20a302Sas200622 		break;
715dc20a302Sas200622 
716dc20a302Sas200622 	default:
717dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
718dc20a302Sas200622 		return (0);
719dc20a302Sas200622 	}
720dc20a302Sas200622 
721dc20a302Sas200622 	bzero(&myref, sizeof (myref));
7228d7e4166Sjose borrego 	myref.stream = nds;
723dc20a302Sas200622 	myref.enclosing = outer_ref;
724dc20a302Sas200622 	myref.ti = outer_ref->ti;
725dc20a302Sas200622 	myref.datum = outer_ref->datum;
726dc20a302Sas200622 	myref.name = "FIXED-VALUE";
727dc20a302Sas200622 	myref.outer_flags = NDR_F_NONE;
728dc20a302Sas200622 	myref.inner_flags = NDR_F_NONE;
729dc20a302Sas200622 
730dc20a302Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
731dc20a302Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
732dc20a302Sas200622 
7338d7e4166Sjose borrego 	rc = ndr_inner(&myref);
734dc20a302Sas200622 	if (!rc)
735dc20a302Sas200622 		return (rc);		/* error already set */
736dc20a302Sas200622 
7378d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
738dc20a302Sas200622 	return (1);
739dc20a302Sas200622 }
740dc20a302Sas200622 
741dc20a302Sas200622 int
7428d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref)
743dc20a302Sas200622 {
7448d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
7458d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
7468d7e4166Sjose borrego 	ndr_ref_t	myref;
747dc20a302Sas200622 	char 		*valp = NULL;
748dc20a302Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
749dc20a302Sas200622 	int		is_union = NDR_IS_UNION(ti);
750dc20a302Sas200622 	int		is_string = NDR_IS_STRING(ti);
751dc20a302Sas200622 	int		rc;
752dc20a302Sas200622 	unsigned	n_hdr;
753dc20a302Sas200622 	unsigned	n_fixed;
754dc20a302Sas200622 	unsigned	n_variable;
755dc20a302Sas200622 	unsigned	n_alloc;
756dc20a302Sas200622 	unsigned	n_pdu_total;
757dc20a302Sas200622 	int		params;
758dc20a302Sas200622 
759dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
760dc20a302Sas200622 
761dc20a302Sas200622 	assert(!is_varlen && !is_string && !is_union);
762dc20a302Sas200622 	assert(params == NDR_F_DIMENSION_IS);
763dc20a302Sas200622 
764dc20a302Sas200622 	/* no header for this */
765dc20a302Sas200622 	n_hdr = 0;
766dc20a302Sas200622 
767dc20a302Sas200622 	/* fixed part -- exactly dimension_is of these */
768dc20a302Sas200622 	n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
769dc20a302Sas200622 	assert(n_fixed > 0);
770dc20a302Sas200622 
771dc20a302Sas200622 	/* variable part -- exactly none of these */
772dc20a302Sas200622 	n_variable = 0;
773dc20a302Sas200622 
774dc20a302Sas200622 	/* sum them up to determine the PDU space required */
775dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
776dc20a302Sas200622 
777dc20a302Sas200622 	/* similar sum to determine how much local memory is required */
778dc20a302Sas200622 	n_alloc = n_fixed + n_variable;
779dc20a302Sas200622 
7808d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
781dc20a302Sas200622 	if (!rc)
782dc20a302Sas200622 		return (rc);		/* error already set */
783dc20a302Sas200622 
7848d7e4166Sjose borrego 	switch (nds->m_op) {
785dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
786dc20a302Sas200622 		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)
792dc20a302Sas200622 			assert(valp == *outer_ref->backptr);
793dc20a302Sas200622 		break;
794dc20a302Sas200622 
795dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
7968d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
797dc20a302Sas200622 		if (!valp) {
798dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
799dc20a302Sas200622 			return (0);
800dc20a302Sas200622 		}
801dc20a302Sas200622 		if (outer_ref->backptr)
802dc20a302Sas200622 			*outer_ref->backptr = valp;
803dc20a302Sas200622 		outer_ref->datum = valp;
804dc20a302Sas200622 		break;
805dc20a302Sas200622 
806dc20a302Sas200622 	default:
807dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
808dc20a302Sas200622 		return (0);
809dc20a302Sas200622 	}
810dc20a302Sas200622 
811dc20a302Sas200622 	bzero(&myref, sizeof (myref));
8128d7e4166Sjose borrego 	myref.stream = nds;
813dc20a302Sas200622 	myref.enclosing = outer_ref;
814dc20a302Sas200622 	myref.ti = outer_ref->ti;
815dc20a302Sas200622 	myref.datum = outer_ref->datum;
816dc20a302Sas200622 	myref.name = "FIXED-ARRAY";
817dc20a302Sas200622 	myref.outer_flags = NDR_F_NONE;
818dc20a302Sas200622 	myref.inner_flags = NDR_F_DIMENSION_IS;
819dc20a302Sas200622 	myref.dimension_is = outer_ref->dimension_is;
820dc20a302Sas200622 
821dc20a302Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
822dc20a302Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
823dc20a302Sas200622 
8248d7e4166Sjose borrego 	rc = ndr_inner(&myref);
825dc20a302Sas200622 	if (!rc)
826dc20a302Sas200622 		return (rc);		/* error already set */
827dc20a302Sas200622 
8288d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
829dc20a302Sas200622 	return (1);
830dc20a302Sas200622 }
831dc20a302Sas200622 
832dc20a302Sas200622 int
8338d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref)
834dc20a302Sas200622 {
8358d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
8368d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
8378d7e4166Sjose borrego 	ndr_ref_t	myref;
838dc20a302Sas200622 	char 		*valp = NULL;
839dc20a302Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
840dc20a302Sas200622 	int		is_union = NDR_IS_UNION(ti);
841dc20a302Sas200622 	int		is_string = NDR_IS_STRING(ti);
842dc20a302Sas200622 	unsigned long	size_is;
843dc20a302Sas200622 	int		rc;
844dc20a302Sas200622 	unsigned	n_hdr;
845dc20a302Sas200622 	unsigned	n_fixed;
846dc20a302Sas200622 	unsigned	n_variable;
847dc20a302Sas200622 	unsigned	n_alloc;
848dc20a302Sas200622 	unsigned	n_pdu_total;
849f96bd5c8SAlan Wright 	unsigned	n_ptr_offset;
850dc20a302Sas200622 	int		params;
851dc20a302Sas200622 
852dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
853dc20a302Sas200622 
854dc20a302Sas200622 	assert(!is_varlen && !is_string && !is_union);
855f96bd5c8SAlan Wright 	assert(params & NDR_F_SIZE_IS);
856dc20a302Sas200622 
857dc20a302Sas200622 	/* conformant header for this */
858dc20a302Sas200622 	n_hdr = 4;
859dc20a302Sas200622 
860dc20a302Sas200622 	/* fixed part -- exactly none of these */
861dc20a302Sas200622 	n_fixed = 0;
862dc20a302Sas200622 
863dc20a302Sas200622 	/* variable part -- exactly size_of of these */
864dc20a302Sas200622 	/* notice that it is the **fixed** size of the ti */
865dc20a302Sas200622 	n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
866dc20a302Sas200622 
867dc20a302Sas200622 	/* sum them up to determine the PDU space required */
868dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
869dc20a302Sas200622 
870dc20a302Sas200622 	/* similar sum to determine how much local memory is required */
871dc20a302Sas200622 	n_alloc = n_fixed + n_variable;
872dc20a302Sas200622 
8738d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
874dc20a302Sas200622 	if (!rc)
875dc20a302Sas200622 		return (rc);		/* error already set */
876dc20a302Sas200622 
8778d7e4166Sjose borrego 	switch (nds->m_op) {
878dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
879dc20a302Sas200622 		size_is = outer_ref->size_is;
8808d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
881dc20a302Sas200622 		if (!rc)
882dc20a302Sas200622 			return (0);	/* error already set */
883dc20a302Sas200622 
884dc20a302Sas200622 		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)
890dc20a302Sas200622 			assert(valp == *outer_ref->backptr);
891f96bd5c8SAlan Wright 		n_ptr_offset = 4;
892dc20a302Sas200622 		break;
893dc20a302Sas200622 
894dc20a302Sas200622 	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 */
9008d7e4166Sjose borrego 			rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
901dc20a302Sas200622 			if (!rc)
902dc20a302Sas200622 				return (0);	/* error already set */
903dc20a302Sas200622 
904dc20a302Sas200622 			if (size_is != outer_ref->size_is) {
905dc20a302Sas200622 				NDR_SET_ERROR(outer_ref,
906dc20a302Sas200622 				    NDR_ERR_SIZE_IS_MISMATCH_PDU);
907dc20a302Sas200622 				return (0);
908dc20a302Sas200622 			}
909dc20a302Sas200622 
910f96bd5c8SAlan Wright 			n_ptr_offset = 4;
911f96bd5c8SAlan Wright 		}
912f96bd5c8SAlan Wright 
9133ad684d6Sjb150015 		if (size_is > 0) {
9148d7e4166Sjose borrego 			valp = NDS_MALLOC(nds, n_alloc, outer_ref);
915dc20a302Sas200622 			if (!valp) {
916dc20a302Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
917dc20a302Sas200622 				return (0);
918dc20a302Sas200622 			}
9193ad684d6Sjb150015 		}
9203ad684d6Sjb150015 
921dc20a302Sas200622 		if (outer_ref->backptr)
922dc20a302Sas200622 			*outer_ref->backptr = valp;
923dc20a302Sas200622 		outer_ref->datum = valp;
924dc20a302Sas200622 		break;
925dc20a302Sas200622 
926dc20a302Sas200622 	default:
927dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
928dc20a302Sas200622 		return (0);
929dc20a302Sas200622 	}
930dc20a302Sas200622 
9313ad684d6Sjb150015 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
9323ad684d6Sjb150015 	outer_ref->type_flags = NDR_F_NONE;
9333ad684d6Sjb150015 	outer_ref->inner_flags = NDR_F_NONE;
9343ad684d6Sjb150015 
9353ad684d6Sjb150015 	if (size_is > 0) {
936dc20a302Sas200622 		bzero(&myref, sizeof (myref));
9378d7e4166Sjose borrego 		myref.stream = nds;
938dc20a302Sas200622 		myref.enclosing = outer_ref;
939dc20a302Sas200622 		myref.ti = outer_ref->ti;
940dc20a302Sas200622 		myref.datum = outer_ref->datum;
941dc20a302Sas200622 		myref.name = "CONFORMANT-ARRAY";
942dc20a302Sas200622 		myref.outer_flags = NDR_F_NONE;
943dc20a302Sas200622 		myref.inner_flags = NDR_F_SIZE_IS;
944dc20a302Sas200622 		myref.size_is = outer_ref->size_is;
945dc20a302Sas200622 
946dc20a302Sas200622 		myref.inner_flags = NDR_F_DIMENSION_IS;		/* convenient */
947dc20a302Sas200622 		myref.dimension_is = outer_ref->size_is;	/* convenient */
948dc20a302Sas200622 
949f96bd5c8SAlan Wright 		myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
950dc20a302Sas200622 
9518d7e4166Sjose borrego 		rc = ndr_inner(&myref);
952dc20a302Sas200622 		if (!rc)
953dc20a302Sas200622 			return (rc);		/* error already set */
9543ad684d6Sjb150015 	}
955dc20a302Sas200622 
9568d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
957dc20a302Sas200622 	return (1);
958dc20a302Sas200622 }
959dc20a302Sas200622 
960dc20a302Sas200622 int
9618d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
962dc20a302Sas200622 {
9638d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
9648d7e4166Sjose borrego 	ndr_typeinfo_t	*ti = outer_ref->ti;
9658d7e4166Sjose borrego 	ndr_ref_t	myref;
966dc20a302Sas200622 	char 		*valp = NULL;
967dc20a302Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
968dc20a302Sas200622 	int		is_union = NDR_IS_UNION(ti);
969dc20a302Sas200622 	int		is_string = NDR_IS_STRING(ti);
970dc20a302Sas200622 	unsigned long	size_is;
971dc20a302Sas200622 	int		rc;
972dc20a302Sas200622 	unsigned	n_hdr;
973dc20a302Sas200622 	unsigned	n_fixed;
974dc20a302Sas200622 	unsigned	n_variable;
975dc20a302Sas200622 	unsigned	n_alloc;
976dc20a302Sas200622 	unsigned	n_pdu_total;
977dc20a302Sas200622 	int		params;
978dc20a302Sas200622 
979dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
980dc20a302Sas200622 
981dc20a302Sas200622 	assert(is_varlen && !is_string && !is_union);
982dc20a302Sas200622 	assert(params == NDR_F_NONE);
983dc20a302Sas200622 
984dc20a302Sas200622 	/* conformant header for this */
985dc20a302Sas200622 	n_hdr = 4;
986dc20a302Sas200622 
987dc20a302Sas200622 	/* fixed part -- exactly one of these */
988dc20a302Sas200622 	n_fixed = ti->pdu_size_fixed_part;
989dc20a302Sas200622 
990dc20a302Sas200622 	/* variable part -- exactly size_of of these */
991dc20a302Sas200622 	n_variable = 0;		/* 0 for the moment */
992dc20a302Sas200622 
993dc20a302Sas200622 	/* sum them up to determine the PDU space required */
994dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
995dc20a302Sas200622 
996dc20a302Sas200622 	/* similar sum to determine how much local memory is required */
997dc20a302Sas200622 	n_alloc = n_fixed + n_variable;
998dc20a302Sas200622 
999dc20a302Sas200622 	/* For the moment, grow enough for the fixed-size part */
10008d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1001dc20a302Sas200622 	if (!rc)
1002dc20a302Sas200622 		return (rc);		/* error already set */
1003dc20a302Sas200622 
10048d7e4166Sjose borrego 	switch (nds->m_op) {
1005dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1006dc20a302Sas200622 		/*
1007dc20a302Sas200622 		 * We don't know the size yet. We have to wait for
1008dc20a302Sas200622 		 * it. Proceed with the fixed-size part, and await
10098d7e4166Sjose borrego 		 * the call to ndr_size_is().
1010dc20a302Sas200622 		 */
1011dc20a302Sas200622 		size_is = 0;
10128d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1013dc20a302Sas200622 		if (!rc)
1014dc20a302Sas200622 			return (0);	/* error already set */
1015dc20a302Sas200622 
1016dc20a302Sas200622 		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)
1022dc20a302Sas200622 			assert(valp == *outer_ref->backptr);
1023dc20a302Sas200622 		break;
1024dc20a302Sas200622 
1025dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1026dc20a302Sas200622 		/*
1027dc20a302Sas200622 		 * We know the size of the variable part because
1028dc20a302Sas200622 		 * of the CONFORMANT header. We will verify
1029dc20a302Sas200622 		 * the header against the [size_is(X)] advice
10308d7e4166Sjose borrego 		 * later when ndr_size_is() is called.
1031dc20a302Sas200622 		 */
10328d7e4166Sjose borrego 		rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
1033dc20a302Sas200622 		if (!rc)
1034dc20a302Sas200622 			return (0);	/* error already set */
1035dc20a302Sas200622 
1036dc20a302Sas200622 		/* recalculate metrics */
1037dc20a302Sas200622 		n_variable = size_is * ti->pdu_size_variable_part;
1038dc20a302Sas200622 		n_pdu_total = n_hdr + n_fixed + n_variable;
1039dc20a302Sas200622 		n_alloc = n_fixed + n_variable;
1040dc20a302Sas200622 
10418d7e4166Sjose borrego 		rc = ndr_outer_grow(outer_ref, n_pdu_total);
1042dc20a302Sas200622 		if (!rc)
1043dc20a302Sas200622 			return (rc);		/* error already set */
1044dc20a302Sas200622 
1045dc20a302Sas200622 		outer_ref->size_is = size_is; /* verified later */
1046dc20a302Sas200622 
10478d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1048dc20a302Sas200622 		if (!valp) {
1049dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1050dc20a302Sas200622 			return (0);
1051dc20a302Sas200622 		}
1052dc20a302Sas200622 		if (outer_ref->backptr)
1053dc20a302Sas200622 			*outer_ref->backptr = valp;
1054dc20a302Sas200622 		outer_ref->datum = valp;
1055dc20a302Sas200622 		break;
1056dc20a302Sas200622 
1057dc20a302Sas200622 	default:
1058dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1059dc20a302Sas200622 		return (0);
1060dc20a302Sas200622 	}
1061dc20a302Sas200622 
10623ad684d6Sjb150015 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
10633ad684d6Sjb150015 	outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
10643ad684d6Sjb150015 	outer_ref->inner_flags = NDR_F_NONE;   /* indicate pending */
10653ad684d6Sjb150015 
1066dc20a302Sas200622 	bzero(&myref, sizeof (myref));
10678d7e4166Sjose borrego 	myref.stream = nds;
1068dc20a302Sas200622 	myref.enclosing = outer_ref;
1069dc20a302Sas200622 	myref.ti = outer_ref->ti;
1070dc20a302Sas200622 	myref.datum = outer_ref->datum;
1071dc20a302Sas200622 	myref.name = "CONFORMANT-CONSTRUCT";
1072dc20a302Sas200622 	myref.outer_flags = NDR_F_NONE;
1073dc20a302Sas200622 	myref.inner_flags = NDR_F_NONE;
1074dc20a302Sas200622 	myref.size_is = outer_ref->size_is;
1075dc20a302Sas200622 
1076dc20a302Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 4;
1077dc20a302Sas200622 
10788d7e4166Sjose borrego 	rc = ndr_inner(&myref);
1079dc20a302Sas200622 	if (!rc)
1080dc20a302Sas200622 		return (rc);		/* error already set */
1081dc20a302Sas200622 
10828d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1083dc20a302Sas200622 
1084dc20a302Sas200622 	if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
1085dc20a302Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
1086dc20a302Sas200622 		return (0);
1087dc20a302Sas200622 	}
1088dc20a302Sas200622 
1089dc20a302Sas200622 	return (1);
1090dc20a302Sas200622 }
1091dc20a302Sas200622 
1092dc20a302Sas200622 int
10938d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref)
1094dc20a302Sas200622 {
10958d7e4166Sjose borrego 	ndr_stream_t 		*nds = ref->stream;
10968d7e4166Sjose borrego 	ndr_ref_t 		*outer_ref = nds->outer_current;
10978d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = outer_ref->ti;
1098dc20a302Sas200622 	unsigned long		size_is;
1099dc20a302Sas200622 	int			rc;
1100dc20a302Sas200622 	unsigned		n_hdr;
1101dc20a302Sas200622 	unsigned		n_fixed;
1102dc20a302Sas200622 	unsigned		n_variable;
1103dc20a302Sas200622 	unsigned		n_pdu_total;
1104dc20a302Sas200622 
1105dc20a302Sas200622 	assert(ref->inner_flags & NDR_F_SIZE_IS);
1106dc20a302Sas200622 	size_is = ref->size_is;
1107dc20a302Sas200622 
1108dc20a302Sas200622 	if (outer_ref->type_flags != NDR_F_SIZE_IS) {
1109dc20a302Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
1110dc20a302Sas200622 		return (0);
1111dc20a302Sas200622 	}
1112dc20a302Sas200622 
1113dc20a302Sas200622 	if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
1114dc20a302Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
1115dc20a302Sas200622 		return (0);
1116dc20a302Sas200622 	}
1117dc20a302Sas200622 
11188d7e4166Sjose borrego 	/* repeat metrics, see ndr_conformant_construct() above */
1119dc20a302Sas200622 	n_hdr = 4;
1120dc20a302Sas200622 	n_fixed = ti->pdu_size_fixed_part;
1121dc20a302Sas200622 	n_variable = size_is * ti->pdu_size_variable_part;
1122dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
1123dc20a302Sas200622 
11248d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1125dc20a302Sas200622 	if (!rc)
1126dc20a302Sas200622 		return (rc);		/* error already set */
1127dc20a302Sas200622 
11288d7e4166Sjose borrego 	switch (nds->m_op) {
1129dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1130dc20a302Sas200622 		/*
1131dc20a302Sas200622 		 * We have to set the sizing header and extend
1132dc20a302Sas200622 		 * the size of the PDU (already done).
1133dc20a302Sas200622 		 */
11348d7e4166Sjose borrego 		rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1135dc20a302Sas200622 		if (!rc)
1136dc20a302Sas200622 			return (0);	/* error already set */
1137dc20a302Sas200622 		break;
1138dc20a302Sas200622 
1139dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1140dc20a302Sas200622 		/*
11418d7e4166Sjose borrego 		 * Allocation done during ndr_conformant_construct().
1142dc20a302Sas200622 		 * All we are doing here is verifying that the
1143dc20a302Sas200622 		 * intended size (ref->size_is) matches the sizing header.
1144dc20a302Sas200622 		 */
1145dc20a302Sas200622 		if (size_is != outer_ref->size_is) {
1146dc20a302Sas200622 			NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
1147dc20a302Sas200622 			return (0);
1148dc20a302Sas200622 		}
1149dc20a302Sas200622 		break;
1150dc20a302Sas200622 
1151dc20a302Sas200622 	default:
1152dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1153dc20a302Sas200622 		return (0);
1154dc20a302Sas200622 	}
1155dc20a302Sas200622 
1156dc20a302Sas200622 	outer_ref->inner_flags |= NDR_F_SIZE_IS;
1157dc20a302Sas200622 	outer_ref->size_is = ref->size_is;
1158dc20a302Sas200622 	return (1);
1159dc20a302Sas200622 }
1160dc20a302Sas200622 
1161dc20a302Sas200622 int
11628d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref)
1163dc20a302Sas200622 {
11648d7e4166Sjose borrego 	ndr_stream_t	*nds = outer_ref->stream;
11658d7e4166Sjose borrego 	ndr_typeinfo_t 	*ti = outer_ref->ti;
11668d7e4166Sjose borrego 	ndr_ref_t	myref;
1167dc20a302Sas200622 	char 		*valp = NULL;
1168dc20a302Sas200622 	unsigned	is_varlen = ti->pdu_size_variable_part;
1169dc20a302Sas200622 	int		is_union = NDR_IS_UNION(ti);
1170dc20a302Sas200622 	int		is_string = NDR_IS_STRING(ti);
1171dc20a302Sas200622 	int		rc;
1172dc20a302Sas200622 	unsigned	n_zeroes;
1173dc20a302Sas200622 	unsigned	ix;
1174dc20a302Sas200622 	unsigned long	size_is;
1175dc20a302Sas200622 	unsigned long	first_is;
1176dc20a302Sas200622 	unsigned long	length_is;
1177dc20a302Sas200622 	unsigned	n_hdr;
1178dc20a302Sas200622 	unsigned	n_fixed;
1179dc20a302Sas200622 	unsigned	n_variable;
1180dc20a302Sas200622 	unsigned	n_alloc;
1181dc20a302Sas200622 	unsigned	n_pdu_total;
1182dc20a302Sas200622 	int		params;
1183dc20a302Sas200622 
1184dc20a302Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1185dc20a302Sas200622 
1186dc20a302Sas200622 	assert(is_varlen && is_string && !is_union);
1187dc20a302Sas200622 	assert(params == NDR_F_NONE);
1188dc20a302Sas200622 
1189dc20a302Sas200622 	/* string header for this: size_is first_is length_is */
1190dc20a302Sas200622 	n_hdr = 12;
1191dc20a302Sas200622 
1192dc20a302Sas200622 	/* fixed part -- exactly none of these */
1193dc20a302Sas200622 	n_fixed = 0;
1194dc20a302Sas200622 
11958d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_hdr))
1196dc20a302Sas200622 		return (0);		/* error already set */
1197dc20a302Sas200622 
11988d7e4166Sjose borrego 	switch (nds->m_op) {
1199dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1200dc20a302Sas200622 		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 		}
1205dc20a302Sas200622 
1206dc20a302Sas200622 		if (outer_ref->backptr)
1207dc20a302Sas200622 			assert(valp == *outer_ref->backptr);
1208dc20a302Sas200622 
1209dc20a302Sas200622 		if (ti == &ndt_s_wchar) {
1210dc20a302Sas200622 			/*
1211a0aa776eSAlan Wright 			 * size_is is the number of characters in the
1212a0aa776eSAlan Wright 			 * (multibyte) string, including the null.
1213dc20a302Sas200622 			 */
1214fe1c642dSBill Krier 			size_is = smb_wcequiv_strlen(valp) /
1215fe1c642dSBill Krier 			    sizeof (smb_wchar_t);
1216fe1c642dSBill Krier 
1217fe1c642dSBill Krier 			if (!(nds->flags & NDS_F_NONULL))
1218fe1c642dSBill Krier 				++size_is;
1219dc20a302Sas200622 
1220dc20a302Sas200622 			if (size_is > NDR_STRING_MAX) {
1221dc20a302Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1222dc20a302Sas200622 				return (0);
1223dc20a302Sas200622 			}
1224dc20a302Sas200622 		} else {
1225dc20a302Sas200622 			valp = outer_ref->datum;
1226dc20a302Sas200622 			n_zeroes = 0;
1227f96bd5c8SAlan Wright 			for (ix = 0; ix < NDR_STRING_MAX; ix++) {
1228dc20a302Sas200622 				if (valp[ix] == 0) {
1229dc20a302Sas200622 					n_zeroes++;
1230dc20a302Sas200622 					if (n_zeroes >= is_varlen &&
1231dc20a302Sas200622 					    ix % is_varlen == 0) {
1232dc20a302Sas200622 						break;
1233dc20a302Sas200622 					}
1234dc20a302Sas200622 				} else {
1235dc20a302Sas200622 					n_zeroes = 0;
1236dc20a302Sas200622 				}
1237dc20a302Sas200622 			}
1238f96bd5c8SAlan Wright 			if (ix >= NDR_STRING_MAX) {
1239dc20a302Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1240dc20a302Sas200622 				return (0);
1241dc20a302Sas200622 			}
1242dc20a302Sas200622 			size_is = ix+1;
1243dc20a302Sas200622 		}
1244dc20a302Sas200622 
1245dc20a302Sas200622 		first_is = 0;
1246dc20a302Sas200622 
12478d7e4166Sjose borrego 		if (nds->flags & NDS_F_NOTERM)
1248dc20a302Sas200622 			length_is = size_is - 1;
1249dc20a302Sas200622 		else
1250dc20a302Sas200622 			length_is = size_is;
1251dc20a302Sas200622 
12528d7e4166Sjose borrego 		if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
12538d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
12548d7e4166Sjose borrego 		    !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
1255dc20a302Sas200622 			return (0);		/* error already set */
1256dc20a302Sas200622 		break;
1257dc20a302Sas200622 
1258dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
12598d7e4166Sjose borrego 		if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
12608d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
12618d7e4166Sjose borrego 		    !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
1262dc20a302Sas200622 			return (0);		/* error already set */
1263dc20a302Sas200622 
1264dc20a302Sas200622 		/*
1265dc20a302Sas200622 		 * In addition to the first_is check, we used to check that
1266dc20a302Sas200622 		 * size_is or size_is-1 was equal to length_is but Windows95
1267dc20a302Sas200622 		 * doesn't conform to this "rule" (see variable part below).
1268dc20a302Sas200622 		 * The srvmgr tool for Windows95 sent the following values
1269dc20a302Sas200622 		 * for a path string:
1270dc20a302Sas200622 		 *
1271dc20a302Sas200622 		 *	size_is   = 261 (0x105)
1272dc20a302Sas200622 		 *	first_is  = 0
1273dc20a302Sas200622 		 *	length_is = 53  (0x35)
1274dc20a302Sas200622 		 *
1275dc20a302Sas200622 		 * The length_is was correct (for the given path) but the
1276dc20a302Sas200622 		 * size_is was the maximum path length rather than being
1277dc20a302Sas200622 		 * related to length_is.
1278dc20a302Sas200622 		 */
1279dc20a302Sas200622 		if (first_is != 0) {
1280dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1281dc20a302Sas200622 			return (0);
1282dc20a302Sas200622 		}
1283dc20a302Sas200622 
1284dc20a302Sas200622 		if (ti == &ndt_s_wchar) {
1285dc20a302Sas200622 			/*
1286dc20a302Sas200622 			 * Decoding Unicode to UTF-8; we need to allow
1287dc20a302Sas200622 			 * for the maximum possible char size. It would
1288dc20a302Sas200622 			 * be nice to use mbequiv_strlen but the string
1289dc20a302Sas200622 			 * may not be null terminated.
1290dc20a302Sas200622 			 */
1291dc20a302Sas200622 			n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
1292dc20a302Sas200622 		} else {
1293dc20a302Sas200622 			n_alloc = (size_is + 1) * is_varlen;
1294dc20a302Sas200622 		}
1295dc20a302Sas200622 
12968d7e4166Sjose borrego 		valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1297dc20a302Sas200622 		if (!valp) {
1298dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1299dc20a302Sas200622 			return (0);
1300dc20a302Sas200622 		}
1301dc20a302Sas200622 
1302dc20a302Sas200622 		bzero(valp, (size_is+1) * is_varlen);
1303dc20a302Sas200622 
1304dc20a302Sas200622 		if (outer_ref->backptr)
1305dc20a302Sas200622 			*outer_ref->backptr = valp;
1306dc20a302Sas200622 		outer_ref->datum = valp;
1307dc20a302Sas200622 		break;
1308dc20a302Sas200622 
1309dc20a302Sas200622 	default:
1310dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1311dc20a302Sas200622 		return (0);
1312dc20a302Sas200622 	}
1313dc20a302Sas200622 
1314dc20a302Sas200622 	/*
1315dc20a302Sas200622 	 * Variable part - exactly length_is of these.
1316dc20a302Sas200622 	 *
1317dc20a302Sas200622 	 * Usually, length_is is same as size_is and includes nul.
1318dc20a302Sas200622 	 * Some protocols use length_is = size_is-1, and length_is does
1319dc20a302Sas200622 	 * not include the nul (which is more consistent with DCE spec).
1320dc20a302Sas200622 	 * If the length_is is 0, there is no data following the
1321dc20a302Sas200622 	 * sizing header, regardless of size_is.
1322dc20a302Sas200622 	 */
1323dc20a302Sas200622 	n_variable = length_is * is_varlen;
1324dc20a302Sas200622 
1325dc20a302Sas200622 	/* sum them up to determine the PDU space required */
1326dc20a302Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
1327dc20a302Sas200622 
1328dc20a302Sas200622 	/* similar sum to determine how much local memory is required */
1329dc20a302Sas200622 	n_alloc = n_fixed + n_variable;
1330dc20a302Sas200622 
13318d7e4166Sjose borrego 	rc = ndr_outer_grow(outer_ref, n_pdu_total);
1332dc20a302Sas200622 	if (!rc)
1333dc20a302Sas200622 		return (rc);		/* error already set */
1334dc20a302Sas200622 
1335dc20a302Sas200622 	if (length_is > 0) {
1336dc20a302Sas200622 		bzero(&myref, sizeof (myref));
13378d7e4166Sjose borrego 		myref.stream = nds;
1338dc20a302Sas200622 		myref.enclosing = outer_ref;
1339dc20a302Sas200622 		myref.ti = outer_ref->ti;
1340dc20a302Sas200622 		myref.datum = outer_ref->datum;
1341dc20a302Sas200622 		myref.name = "OUTER-STRING";
1342dc20a302Sas200622 		myref.outer_flags = NDR_F_IS_STRING;
1343dc20a302Sas200622 		myref.inner_flags = NDR_F_NONE;
1344dc20a302Sas200622 
1345dc20a302Sas200622 		/*
13468d7e4166Sjose borrego 		 * Set up size_is and strlen_is for ndr_s_wchar.
1347dc20a302Sas200622 		 */
1348dc20a302Sas200622 		myref.size_is = size_is;
1349dc20a302Sas200622 		myref.strlen_is = length_is;
1350dc20a302Sas200622 	}
1351dc20a302Sas200622 
1352dc20a302Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 12;
1353dc20a302Sas200622 
1354dc20a302Sas200622 	/*
1355dc20a302Sas200622 	 * Don't try to decode empty strings.
1356dc20a302Sas200622 	 */
1357dc20a302Sas200622 	if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
13588d7e4166Sjose borrego 		nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1359dc20a302Sas200622 		return (1);
1360dc20a302Sas200622 	}
1361dc20a302Sas200622 
1362dc20a302Sas200622 	if ((size_is != 0) && (length_is != 0)) {
13638d7e4166Sjose borrego 		rc = ndr_inner(&myref);
1364dc20a302Sas200622 		if (!rc)
1365dc20a302Sas200622 			return (rc);		/* error already set */
1366dc20a302Sas200622 	}
1367dc20a302Sas200622 
13688d7e4166Sjose borrego 	nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1369dc20a302Sas200622 	return (1);
1370dc20a302Sas200622 }
1371dc20a302Sas200622 
1372dc20a302Sas200622 int
13738d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
1374dc20a302Sas200622     unsigned long *sizing_p)
1375dc20a302Sas200622 {
13768d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
1377dc20a302Sas200622 	unsigned long	pdu_offset;
1378dc20a302Sas200622 	int		rc;
1379dc20a302Sas200622 
1380dc20a302Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
1381dc20a302Sas200622 
13828d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
13838d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
13848d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1385dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1386dc20a302Sas200622 		return (0);
1387dc20a302Sas200622 	}
1388dc20a302Sas200622 
13898d7e4166Sjose borrego 	switch (nds->m_op) {
1390dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1391dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1392dc20a302Sas200622 		return (0);
1393dc20a302Sas200622 
1394dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
13958d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
13968d7e4166Sjose borrego 		    nds->swap, outer_ref);
1397dc20a302Sas200622 		break;
1398dc20a302Sas200622 
1399dc20a302Sas200622 	default:
1400dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1401dc20a302Sas200622 		return (0);
1402dc20a302Sas200622 	}
1403dc20a302Sas200622 
1404dc20a302Sas200622 	return (rc);
1405dc20a302Sas200622 }
1406dc20a302Sas200622 
1407dc20a302Sas200622 int
14088d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
1409dc20a302Sas200622     unsigned long *sizing_p)
1410dc20a302Sas200622 {
14118d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
1412dc20a302Sas200622 	unsigned long	pdu_offset;
1413dc20a302Sas200622 	int		rc;
1414dc20a302Sas200622 
1415dc20a302Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
1416dc20a302Sas200622 
14178d7e4166Sjose borrego 	if (pdu_offset < nds->outer_current->pdu_offset ||
14188d7e4166Sjose borrego 	    pdu_offset > nds->outer_current->pdu_end_offset ||
14198d7e4166Sjose borrego 	    pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1420dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1421dc20a302Sas200622 		return (0);
1422dc20a302Sas200622 	}
1423dc20a302Sas200622 
14248d7e4166Sjose borrego 	switch (nds->m_op) {
1425dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
14268d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14278d7e4166Sjose borrego 		    nds->swap, outer_ref);
1428dc20a302Sas200622 		break;
1429dc20a302Sas200622 
1430dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1431dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1432dc20a302Sas200622 		return (0);
1433dc20a302Sas200622 
1434dc20a302Sas200622 	default:
1435dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1436dc20a302Sas200622 		return (0);
1437dc20a302Sas200622 	}
1438dc20a302Sas200622 
1439dc20a302Sas200622 	return (rc);
1440dc20a302Sas200622 }
1441dc20a302Sas200622 
1442dc20a302Sas200622 /*
1443dc20a302Sas200622  * All OUTER constructs begin on a mod4 (dword) boundary - except
1444dc20a302Sas200622  * for the ones that don't: some MSRPC calls appear to use word or
1445dc20a302Sas200622  * packed alignment.  Strings appear to be dword aligned.
1446dc20a302Sas200622  */
1447dc20a302Sas200622 int
14488d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref)
1449dc20a302Sas200622 {
14508d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
1451dc20a302Sas200622 	int		rc;
1452dc20a302Sas200622 	unsigned	n_pad;
1453dc20a302Sas200622 	unsigned	align;
1454dc20a302Sas200622 
1455dc20a302Sas200622 	if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1456dc20a302Sas200622 		align = outer_ref->ti->alignment;
14578d7e4166Sjose borrego 		n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
1458dc20a302Sas200622 	} else {
14598d7e4166Sjose borrego 		n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
1460dc20a302Sas200622 	}
1461dc20a302Sas200622 
1462dc20a302Sas200622 	if (n_pad == 0)
1463dc20a302Sas200622 		return (1);	/* already aligned, often the case */
1464dc20a302Sas200622 
14658d7e4166Sjose borrego 	if (!ndr_outer_grow(outer_ref, n_pad))
1466dc20a302Sas200622 		return (0);	/* error already set */
1467dc20a302Sas200622 
14688d7e4166Sjose borrego 	switch (nds->m_op) {
1469dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
14708d7e4166Sjose borrego 		rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
1471dc20a302Sas200622 		if (!rc) {
1472dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1473dc20a302Sas200622 			return (0);
1474dc20a302Sas200622 		}
1475dc20a302Sas200622 		break;
1476dc20a302Sas200622 
1477dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1478dc20a302Sas200622 		break;
1479dc20a302Sas200622 
1480dc20a302Sas200622 	default:
1481dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1482dc20a302Sas200622 		return (0);
1483dc20a302Sas200622 	}
1484dc20a302Sas200622 
14858d7e4166Sjose borrego 	nds->pdu_scan_offset += n_pad;
1486dc20a302Sas200622 	return (1);
1487dc20a302Sas200622 }
1488dc20a302Sas200622 
1489dc20a302Sas200622 int
14908d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
1491dc20a302Sas200622 {
14928d7e4166Sjose borrego 	ndr_stream_t 	*nds = outer_ref->stream;
1493dc20a302Sas200622 	unsigned long	pdu_want_size;
1494dc20a302Sas200622 	int		rc, is_ok = 0;
1495dc20a302Sas200622 
14968d7e4166Sjose borrego 	pdu_want_size = nds->pdu_scan_offset + n_total;
1497dc20a302Sas200622 
14988d7e4166Sjose borrego 	if (pdu_want_size <= nds->pdu_max_size) {
1499dc20a302Sas200622 		is_ok = 1;
1500dc20a302Sas200622 	}
1501dc20a302Sas200622 
15028d7e4166Sjose borrego 	switch (nds->m_op) {
1503dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1504dc20a302Sas200622 		if (is_ok)
1505dc20a302Sas200622 			break;
15068d7e4166Sjose borrego 		rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
1507dc20a302Sas200622 		if (!rc) {
1508dc20a302Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1509dc20a302Sas200622 			return (0);
1510dc20a302Sas200622 		}
1511dc20a302Sas200622 		break;
1512dc20a302Sas200622 
1513dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1514dc20a302Sas200622 		if (is_ok)
1515dc20a302Sas200622 			break;
1516dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1517dc20a302Sas200622 		return (0);
1518dc20a302Sas200622 
1519dc20a302Sas200622 	default:
1520dc20a302Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1521dc20a302Sas200622 		return (0);
1522dc20a302Sas200622 	}
1523dc20a302Sas200622 
15248d7e4166Sjose borrego 	if (nds->pdu_size < pdu_want_size)
15258d7e4166Sjose borrego 		nds->pdu_size = pdu_want_size;
1526dc20a302Sas200622 
1527dc20a302Sas200622 	outer_ref->pdu_end_offset = pdu_want_size;
1528dc20a302Sas200622 	return (1);
1529dc20a302Sas200622 }
1530dc20a302Sas200622 
1531dc20a302Sas200622 /*
1532dc20a302Sas200622  * INNER ELEMENTS
1533dc20a302Sas200622  *
1534dc20a302Sas200622  * The local datum (arg_ref->datum) already exists, there is no need to
1535dc20a302Sas200622  * malloc() it.  The datum should point at a member of a structure.
1536dc20a302Sas200622  *
15378d7e4166Sjose borrego  * For the most part, ndr_inner() and its helpers are just a sanity
1538dc20a302Sas200622  * check.  The underlying ti->ndr_func() could be called immediately
1539dc20a302Sas200622  * for non-pointer elements.  For the sake of robustness, we detect
1540dc20a302Sas200622  * run-time errors here.  Most of the situations this protects against
1541dc20a302Sas200622  * have already been checked by the IDL compiler.  This is also a
1542dc20a302Sas200622  * common point for processing of all data, and so is a convenient
1543dc20a302Sas200622  * place to work from for debugging.
1544dc20a302Sas200622  */
1545dc20a302Sas200622 int
15468d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref)
1547dc20a302Sas200622 {
15488d7e4166Sjose borrego 	ndr_typeinfo_t 	*ti = arg_ref->ti;
1549dc20a302Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
1550dc20a302Sas200622 	int	is_union = NDR_IS_UNION(ti);
1551dc20a302Sas200622 	int	error = NDR_ERR_INNER_PARAMS_BAD;
1552dc20a302Sas200622 	int	params;
1553dc20a302Sas200622 
1554dc20a302Sas200622 	params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1555dc20a302Sas200622 
1556dc20a302Sas200622 	switch (params) {
1557dc20a302Sas200622 	case NDR_F_NONE:
1558dc20a302Sas200622 		if (is_union) {
1559dc20a302Sas200622 			error = NDR_ERR_SWITCH_VALUE_MISSING;
1560dc20a302Sas200622 			break;
1561dc20a302Sas200622 		}
1562dc20a302Sas200622 		return (*ti->ndr_func)(arg_ref);
1563dc20a302Sas200622 
1564dc20a302Sas200622 	case NDR_F_SIZE_IS:
1565dc20a302Sas200622 	case NDR_F_DIMENSION_IS:
1566dc20a302Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:   /* pointer to something */
1567dc20a302Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1568dc20a302Sas200622 		if (is_varlen) {
1569dc20a302Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1570dc20a302Sas200622 			break;
1571dc20a302Sas200622 		}
1572dc20a302Sas200622 		if (is_union) {
1573dc20a302Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1574dc20a302Sas200622 			break;
1575dc20a302Sas200622 		}
1576dc20a302Sas200622 		if (params & NDR_F_IS_POINTER)
15778d7e4166Sjose borrego 			return (ndr_inner_pointer(arg_ref));
1578dc20a302Sas200622 		else if (params & NDR_F_IS_REFERENCE)
15798d7e4166Sjose borrego 			return (ndr_inner_reference(arg_ref));
1580dc20a302Sas200622 		else
15818d7e4166Sjose borrego 			return (ndr_inner_array(arg_ref));
1582dc20a302Sas200622 
1583dc20a302Sas200622 	case NDR_F_IS_POINTER:	/* type is pointer to one something */
1584dc20a302Sas200622 		if (is_union) {
1585dc20a302Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1586dc20a302Sas200622 			break;
1587dc20a302Sas200622 		}
15888d7e4166Sjose borrego 		return (ndr_inner_pointer(arg_ref));
1589dc20a302Sas200622 
1590dc20a302Sas200622 	case NDR_F_IS_REFERENCE:	/* type is pointer to one something */
1591dc20a302Sas200622 		if (is_union) {
1592dc20a302Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1593dc20a302Sas200622 			break;
1594dc20a302Sas200622 		}
15958d7e4166Sjose borrego 		return (ndr_inner_reference(arg_ref));
1596dc20a302Sas200622 
1597dc20a302Sas200622 	case NDR_F_SWITCH_IS:
1598dc20a302Sas200622 		if (!is_union) {
1599dc20a302Sas200622 			error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1600dc20a302Sas200622 			break;
1601dc20a302Sas200622 		}
1602dc20a302Sas200622 		return (*ti->ndr_func)(arg_ref);
1603dc20a302Sas200622 
1604dc20a302Sas200622 	default:
1605dc20a302Sas200622 		error = NDR_ERR_INNER_PARAMS_BAD;
1606dc20a302Sas200622 		break;
1607dc20a302Sas200622 	}
1608dc20a302Sas200622 
1609dc20a302Sas200622 	/*
1610dc20a302Sas200622 	 * If we get here, something is wrong. Most likely,
1611dc20a302Sas200622 	 * the params flags do not match
1612dc20a302Sas200622 	 */
1613dc20a302Sas200622 	NDR_SET_ERROR(arg_ref, error);
1614dc20a302Sas200622 	return (0);
1615dc20a302Sas200622 }
1616dc20a302Sas200622 
1617dc20a302Sas200622 int
16188d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref)
1619dc20a302Sas200622 {
16208d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1621dc20a302Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1622dc20a302Sas200622 	char 		**valpp = (char **)arg_ref->datum;
16238d7e4166Sjose borrego 	ndr_ref_t 	*outer_ref;
1624dc20a302Sas200622 
16258d7e4166Sjose borrego 	if (!ndr__ulong(arg_ref))
1626dc20a302Sas200622 		return (0);	/* error */
1627dc20a302Sas200622 	if (!*valpp)
1628dc20a302Sas200622 		return (1);	/* NULL pointer */
1629dc20a302Sas200622 
16308d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1631dc20a302Sas200622 	if (!outer_ref)
1632dc20a302Sas200622 		return (0);	/* error already set */
1633dc20a302Sas200622 
1634f96bd5c8SAlan Wright 	/*
1635f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1636f96bd5c8SAlan Wright 	 * Retain pointer flag for conformant arrays.
1637f96bd5c8SAlan Wright 	 */
1638dc20a302Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1639f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1640dc20a302Sas200622 		outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1641f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET
1642dc20a302Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1643dc20a302Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1644dc20a302Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1645dc20a302Sas200622 	}
1646f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */
1647dc20a302Sas200622 
1648dc20a302Sas200622 	outer_ref->backptr = valpp;
1649dc20a302Sas200622 
16508d7e4166Sjose borrego 	switch (nds->m_op) {
1651dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1652dc20a302Sas200622 		outer_ref->datum = *valpp;
1653dc20a302Sas200622 		break;
1654dc20a302Sas200622 
1655dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1656dc20a302Sas200622 		/*
1657dc20a302Sas200622 		 * This is probably wrong if the application allocated
1658dc20a302Sas200622 		 * memory in advance.  Indicate no value for now.
1659dc20a302Sas200622 		 * ONC RPC handles this case.
1660dc20a302Sas200622 		 */
1661dc20a302Sas200622 		*valpp = 0;
1662dc20a302Sas200622 		outer_ref->datum = 0;
1663dc20a302Sas200622 		break;
1664dc20a302Sas200622 	}
1665dc20a302Sas200622 
1666dc20a302Sas200622 	return (1);		/* pointer dereference scheduled */
1667dc20a302Sas200622 }
1668dc20a302Sas200622 
1669dc20a302Sas200622 int
16708d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref)
1671dc20a302Sas200622 {
16728d7e4166Sjose borrego 	ndr_stream_t	*nds = arg_ref->stream;
1673dc20a302Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1674dc20a302Sas200622 	char		**valpp = (char **)arg_ref->datum;
16758d7e4166Sjose borrego 	ndr_ref_t	*outer_ref;
1676dc20a302Sas200622 
16778d7e4166Sjose borrego 	outer_ref = ndr_enter_outer_queue(arg_ref);
1678dc20a302Sas200622 	if (!outer_ref)
1679dc20a302Sas200622 		return (0);	/* error already set */
1680dc20a302Sas200622 
1681f96bd5c8SAlan Wright 	/*
1682f96bd5c8SAlan Wright 	 * Move advice in inner_flags to outer_flags.
1683f96bd5c8SAlan Wright 	 * Retain reference flag for conformant arrays.
1684f96bd5c8SAlan Wright 	 */
1685dc20a302Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1686f96bd5c8SAlan Wright 	if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1687dc20a302Sas200622 		outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1688dc20a302Sas200622 #ifdef NDR_INNER_REF_NOT_YET
1689dc20a302Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1690dc20a302Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1691dc20a302Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1692dc20a302Sas200622 	}
1693dc20a302Sas200622 #endif /* NDR_INNER_REF_NOT_YET */
1694dc20a302Sas200622 
1695dc20a302Sas200622 	outer_ref->backptr = valpp;
1696dc20a302Sas200622 
16978d7e4166Sjose borrego 	switch (nds->m_op) {
1698dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
1699dc20a302Sas200622 		outer_ref->datum = *valpp;
1700dc20a302Sas200622 		break;
1701dc20a302Sas200622 
1702dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
1703dc20a302Sas200622 		/*
1704dc20a302Sas200622 		 * This is probably wrong if the application allocated
1705dc20a302Sas200622 		 * memory in advance.  Indicate no value for now.
1706dc20a302Sas200622 		 * ONC RPC handles this case.
1707dc20a302Sas200622 		 */
1708dc20a302Sas200622 		*valpp = 0;
1709dc20a302Sas200622 		outer_ref->datum = 0;
1710dc20a302Sas200622 		break;
1711dc20a302Sas200622 	}
1712dc20a302Sas200622 
1713dc20a302Sas200622 	return (1);		/* pointer dereference scheduled */
1714dc20a302Sas200622 }
1715dc20a302Sas200622 
1716dc20a302Sas200622 int
17178d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref)
1718dc20a302Sas200622 {
17198d7e4166Sjose borrego 	ndr_typeinfo_t		*ti = encl_ref->ti;
17208d7e4166Sjose borrego 	ndr_ref_t		myref;
1721dc20a302Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1722dc20a302Sas200622 	unsigned long		n_elem;
1723dc20a302Sas200622 	unsigned long		i;
1724dc20a302Sas200622 	char			name[30];
1725dc20a302Sas200622 
1726dc20a302Sas200622 	if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1727dc20a302Sas200622 		/* now is the time to check/set size */
17288d7e4166Sjose borrego 		if (!ndr_size_is(encl_ref))
1729dc20a302Sas200622 			return (0);	/* error already set */
1730dc20a302Sas200622 		n_elem = encl_ref->size_is;
1731dc20a302Sas200622 	} else {
1732dc20a302Sas200622 		assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1733dc20a302Sas200622 		n_elem = encl_ref->dimension_is;
1734dc20a302Sas200622 	}
1735dc20a302Sas200622 
1736dc20a302Sas200622 	bzero(&myref, sizeof (myref));
1737dc20a302Sas200622 	myref.enclosing = encl_ref;
1738dc20a302Sas200622 	myref.stream = encl_ref->stream;
1739dc20a302Sas200622 	myref.packed_alignment = 0;
1740dc20a302Sas200622 	myref.ti = ti;
1741dc20a302Sas200622 	myref.inner_flags = NDR_F_NONE;
1742dc20a302Sas200622 
1743dc20a302Sas200622 	for (i = 0; i < n_elem; i++) {
1744dc20a302Sas200622 		(void) sprintf(name, "[%lu]", i);
1745dc20a302Sas200622 		myref.name = name;
1746dc20a302Sas200622 		myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1747dc20a302Sas200622 		myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1748dc20a302Sas200622 
17498d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1750dc20a302Sas200622 			return (0);
1751dc20a302Sas200622 	}
1752dc20a302Sas200622 
1753dc20a302Sas200622 	return (1);
1754dc20a302Sas200622 }
1755dc20a302Sas200622 
1756dc20a302Sas200622 
1757dc20a302Sas200622 /*
1758dc20a302Sas200622  * BASIC TYPES
1759dc20a302Sas200622  */
1760dc20a302Sas200622 #define	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
17618d7e4166Sjose borrego     extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
17628d7e4166Sjose borrego     ndr_typeinfo_t ndt_##TYPE = { \
1763dc20a302Sas200622 	1,		/* NDR version */ \
1764dc20a302Sas200622 	(SIZE)-1,	/* alignment */ \
1765dc20a302Sas200622 	NDR_F_NONE,	/* flags */ \
17668d7e4166Sjose borrego 	ndr_##TYPE,	/* ndr_func */ \
1767dc20a302Sas200622 	SIZE,		/* pdu_size_fixed_part */ \
1768dc20a302Sas200622 	0,		/* pdu_size_variable_part */ \
1769dc20a302Sas200622 	SIZE,		/* c_size_fixed_part */ \
1770dc20a302Sas200622 	0,		/* c_size_variable_part */ \
1771dc20a302Sas200622 	}; \
17728d7e4166Sjose borrego     int ndr_##TYPE(struct ndr_reference *ref) { \
17738d7e4166Sjose borrego 	return (ndr_basic_integer(ref, SIZE)); \
1774dc20a302Sas200622 }
1775dc20a302Sas200622 
1776dc20a302Sas200622 #define	MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
17778d7e4166Sjose borrego     extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
17788d7e4166Sjose borrego     ndr_typeinfo_t ndt_s##TYPE = { \
1779dc20a302Sas200622 	1,		/* NDR version */ \
1780dc20a302Sas200622 	(SIZE)-1,	/* alignment */ \
1781dc20a302Sas200622 	NDR_F_STRING,	/* flags */ \
17828d7e4166Sjose borrego 	ndr_s##TYPE,	/* ndr_func */ \
1783dc20a302Sas200622 	0,		/* pdu_size_fixed_part */ \
1784dc20a302Sas200622 	SIZE,		/* pdu_size_variable_part */ \
1785dc20a302Sas200622 	0,		/* c_size_fixed_part */ \
1786dc20a302Sas200622 	SIZE,		/* c_size_variable_part */ \
1787dc20a302Sas200622 	}; \
17888d7e4166Sjose borrego     int ndr_s##TYPE(struct ndr_reference *ref) { \
17898d7e4166Sjose borrego 	return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
1790dc20a302Sas200622 }
1791dc20a302Sas200622 
1792dc20a302Sas200622 #define	MAKE_BASIC_TYPE(TYPE, SIZE) \
1793dc20a302Sas200622 	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1794dc20a302Sas200622 	MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1795dc20a302Sas200622 
17968d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned);
17978d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
1798dc20a302Sas200622 
1799dc20a302Sas200622 
1800dc20a302Sas200622 MAKE_BASIC_TYPE(_char, 1)
1801dc20a302Sas200622 MAKE_BASIC_TYPE(_uchar, 1)
1802dc20a302Sas200622 MAKE_BASIC_TYPE(_short, 2)
1803dc20a302Sas200622 MAKE_BASIC_TYPE(_ushort, 2)
1804dc20a302Sas200622 MAKE_BASIC_TYPE(_long, 4)
1805dc20a302Sas200622 MAKE_BASIC_TYPE(_ulong, 4)
1806dc20a302Sas200622 
1807dc20a302Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2)
1808dc20a302Sas200622 
1809dc20a302Sas200622 int
18108d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size)
1811dc20a302Sas200622 {
18128d7e4166Sjose borrego 	ndr_stream_t 	*nds = ref->stream;
1813dc20a302Sas200622 	char 		*valp = (char *)ref->datum;
1814dc20a302Sas200622 	int		rc;
1815dc20a302Sas200622 
18168d7e4166Sjose borrego 	switch (nds->m_op) {
1817dc20a302Sas200622 	case NDR_M_OP_MARSHALL:
18188d7e4166Sjose borrego 		rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
18198d7e4166Sjose borrego 		    valp, nds->swap, ref);
1820dc20a302Sas200622 		break;
1821dc20a302Sas200622 
1822dc20a302Sas200622 	case NDR_M_OP_UNMARSHALL:
18238d7e4166Sjose borrego 		rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
18248d7e4166Sjose borrego 		    valp, nds->swap, ref);
1825dc20a302Sas200622 		break;
1826dc20a302Sas200622 
1827dc20a302Sas200622 	default:
1828dc20a302Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1829dc20a302Sas200622 		return (0);
1830dc20a302Sas200622 	}
1831dc20a302Sas200622 
1832dc20a302Sas200622 	return (rc);
1833dc20a302Sas200622 }
1834dc20a302Sas200622 
1835dc20a302Sas200622 int
18368d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
1837dc20a302Sas200622 {
1838dc20a302Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1839dc20a302Sas200622 	unsigned		size = type_under->pdu_size_fixed_part;
1840dc20a302Sas200622 	char			*valp;
18418d7e4166Sjose borrego 	ndr_ref_t		myref;
1842dc20a302Sas200622 	unsigned long		i;
1843dc20a302Sas200622 	long			sense = 0;
1844dc20a302Sas200622 	char			name[30];
1845dc20a302Sas200622 
1846dc20a302Sas200622 	assert(size != 0);
1847dc20a302Sas200622 
1848dc20a302Sas200622 	bzero(&myref, sizeof (myref));
1849dc20a302Sas200622 	myref.enclosing = encl_ref;
1850dc20a302Sas200622 	myref.stream = encl_ref->stream;
1851dc20a302Sas200622 	myref.packed_alignment = 0;
1852dc20a302Sas200622 	myref.ti = type_under;
1853dc20a302Sas200622 	myref.inner_flags = NDR_F_NONE;
1854dc20a302Sas200622 	myref.name = name;
1855dc20a302Sas200622 
1856dc20a302Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
1857dc20a302Sas200622 		(void) sprintf(name, "[%lu]", i);
1858dc20a302Sas200622 		myref.pdu_offset = pdu_offset + i * size;
1859dc20a302Sas200622 		valp = encl_ref->datum + i * size;
1860dc20a302Sas200622 		myref.datum = valp;
1861dc20a302Sas200622 
18628d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1863dc20a302Sas200622 			return (0);
1864dc20a302Sas200622 
1865dc20a302Sas200622 		switch (size) {
1866dc20a302Sas200622 		case 1:		sense = *valp; break;
1867dc20a302Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1868dc20a302Sas200622 		case 2:		sense = *(short *)valp; break;
1869dc20a302Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1870dc20a302Sas200622 		case 4:		sense = *(long *)valp; break;
1871dc20a302Sas200622 		}
1872dc20a302Sas200622 
1873dc20a302Sas200622 		if (!sense)
1874dc20a302Sas200622 			break;
1875dc20a302Sas200622 	}
1876dc20a302Sas200622 
1877dc20a302Sas200622 	return (1);
1878dc20a302Sas200622 }
1879dc20a302Sas200622 
1880dc20a302Sas200622 
18818d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref);
18828d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = {
1883dc20a302Sas200622 	1,		/* NDR version */
1884dc20a302Sas200622 	2-1,		/* alignment */
1885dc20a302Sas200622 	NDR_F_STRING,	/* flags */
18868d7e4166Sjose borrego 	ndr_s_wchar,	/* ndr_func */
1887dc20a302Sas200622 	0,		/* pdu_size_fixed_part */
1888dc20a302Sas200622 	2,		/* pdu_size_variable_part */
1889dc20a302Sas200622 	0,		/* c_size_fixed_part */
1890dc20a302Sas200622 	1,		/* c_size_variable_part */
1891dc20a302Sas200622 };
1892dc20a302Sas200622 
1893dc20a302Sas200622 
1894dc20a302Sas200622 /*
1895dc20a302Sas200622  * Hand coded wchar function because all strings are transported
1896dc20a302Sas200622  * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1897dc20a302Sas200622  * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1898dc20a302Sas200622  * convert from wide characters to multi-byte.
1899dc20a302Sas200622  *
1900dc20a302Sas200622  * It appeared that NT would sometimes leave a spurious character
1901dc20a302Sas200622  * in the data stream before the null wide_char, which would get
1902dc20a302Sas200622  * included in the string decode because we processed until the
1903dc20a302Sas200622  * null character. It now looks like NT does not always terminate
1904dc20a302Sas200622  * RPC Unicode strings and the terminating null is a side effect
1905dc20a302Sas200622  * of field alignment. So now we rely on the strlen_is (set up in
19068d7e4166Sjose borrego  * ndr_outer_string) of the enclosing reference. This may or may
1907dc20a302Sas200622  * not include the null but it doesn't matter, the algorithm will
1908dc20a302Sas200622  * get it right.
1909dc20a302Sas200622  */
1910dc20a302Sas200622 int
19118d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref)
1912dc20a302Sas200622 {
19138d7e4166Sjose borrego 	ndr_stream_t		*nds = encl_ref->stream;
1914dc20a302Sas200622 	unsigned short		wide_char;
1915dc20a302Sas200622 	char 			*valp;
19168d7e4166Sjose borrego 	ndr_ref_t		myref;
1917dc20a302Sas200622 	unsigned long		i;
1918dc20a302Sas200622 	char			name[30];
1919dc20a302Sas200622 	int			count;
1920dc20a302Sas200622 	int			char_count = 0;
1921dc20a302Sas200622 
19228d7e4166Sjose borrego 	if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1923dc20a302Sas200622 		/*
1924dc20a302Sas200622 		 * To avoid problems with zero length strings
1925dc20a302Sas200622 		 * we can just null terminate here and be done.
1926dc20a302Sas200622 		 */
1927dc20a302Sas200622 		if (encl_ref->strlen_is == 0) {
1928dc20a302Sas200622 			encl_ref->datum[0] = '\0';
1929dc20a302Sas200622 			return (1);
1930dc20a302Sas200622 		}
1931dc20a302Sas200622 	}
1932dc20a302Sas200622 
1933dc20a302Sas200622 	bzero(&myref, sizeof (myref));
1934dc20a302Sas200622 	myref.enclosing = encl_ref;
1935dc20a302Sas200622 	myref.stream = encl_ref->stream;
1936dc20a302Sas200622 	myref.packed_alignment = 0;
1937dc20a302Sas200622 	myref.ti = &ndt__wchar;
1938dc20a302Sas200622 	myref.inner_flags = NDR_F_NONE;
1939dc20a302Sas200622 	myref.datum = (char *)&wide_char;
1940dc20a302Sas200622 	myref.name = name;
1941dc20a302Sas200622 	myref.pdu_offset = encl_ref->pdu_offset;
1942dc20a302Sas200622 
1943dc20a302Sas200622 	valp = encl_ref->datum;
1944dc20a302Sas200622 	count = 0;
1945dc20a302Sas200622 
1946dc20a302Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
1947dc20a302Sas200622 		(void) sprintf(name, "[%lu]", i);
1948dc20a302Sas200622 
19498d7e4166Sjose borrego 		if (nds->m_op == NDR_M_OP_MARSHALL) {
1950bbf6f00cSJordan Brown 			count = smb_mbtowc((smb_wchar_t *)&wide_char, valp,
1951dc20a302Sas200622 			    MTS_MB_CHAR_MAX);
1952dc20a302Sas200622 			if (count < 0) {
1953dc20a302Sas200622 				return (0);
1954dc20a302Sas200622 			} else if (count == 0) {
1955dc20a302Sas200622 				if (encl_ref->strlen_is != encl_ref->size_is)
1956dc20a302Sas200622 					break;
1957dc20a302Sas200622 
1958dc20a302Sas200622 				/*
1959dc20a302Sas200622 				 * If the input char is 0, mbtowc
1960dc20a302Sas200622 				 * returns 0 without setting wide_char.
1961dc20a302Sas200622 				 * Set wide_char to 0 and a count of 1.
1962dc20a302Sas200622 				 */
1963dc20a302Sas200622 				wide_char = *valp;
1964dc20a302Sas200622 				count = 1;
1965dc20a302Sas200622 			}
1966dc20a302Sas200622 		}
1967dc20a302Sas200622 
19688d7e4166Sjose borrego 		if (!ndr_inner(&myref))
1969dc20a302Sas200622 			return (0);
1970dc20a302Sas200622 
19718d7e4166Sjose borrego 		if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1972bbf6f00cSJordan Brown 			count = smb_wctomb(valp, wide_char);
1973dc20a302Sas200622 
1974dc20a302Sas200622 			if ((++char_count) == encl_ref->strlen_is) {
1975dc20a302Sas200622 				valp += count;
1976dc20a302Sas200622 				*valp = '\0';
1977dc20a302Sas200622 				break;
1978dc20a302Sas200622 			}
1979dc20a302Sas200622 		}
1980dc20a302Sas200622 
1981dc20a302Sas200622 		if (!wide_char)
1982dc20a302Sas200622 			break;
1983dc20a302Sas200622 
1984dc20a302Sas200622 		myref.pdu_offset += sizeof (wide_char);
1985dc20a302Sas200622 		valp += count;
1986dc20a302Sas200622 	}
1987dc20a302Sas200622 
1988dc20a302Sas200622 	return (1);
1989dc20a302Sas200622 }
1990dc20a302Sas200622 
1991dc20a302Sas200622 /*
1992dc20a302Sas200622  * Converts a multibyte character string to a little-endian, wide-char
1993dc20a302Sas200622  * string.  No more than nwchars wide characters are stored.
1994dc20a302Sas200622  * A terminating null wide character is appended if there is room.
1995dc20a302Sas200622  *
1996dc20a302Sas200622  * Returns the number of wide characters converted, not counting
1997dc20a302Sas200622  * any terminating null wide character.  Returns -1 if an invalid
1998dc20a302Sas200622  * multibyte character is encountered.
1999dc20a302Sas200622  */
2000dc20a302Sas200622 size_t
2001bbf6f00cSJordan Brown ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs,
2002dc20a302Sas200622     size_t nwchars)
2003dc20a302Sas200622 {
2004bbf6f00cSJordan Brown 	smb_wchar_t *start = wcs;
2005dc20a302Sas200622 	int nbytes;
2006dc20a302Sas200622 
2007dc20a302Sas200622 	while (nwchars--) {
20088d7e4166Sjose borrego 		nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX);
2009dc20a302Sas200622 		if (nbytes < 0) {
2010dc20a302Sas200622 			*wcs = 0;
2011dc20a302Sas200622 			return ((size_t)-1);
2012dc20a302Sas200622 		}
2013dc20a302Sas200622 
2014dc20a302Sas200622 		if (*mbs == 0)
2015dc20a302Sas200622 			break;
2016dc20a302Sas200622 
2017dc20a302Sas200622 		++wcs;
2018dc20a302Sas200622 		mbs += nbytes;
2019dc20a302Sas200622 	}
2020dc20a302Sas200622 
2021dc20a302Sas200622 	return (wcs - start);
2022dc20a302Sas200622 }
2023dc20a302Sas200622 
2024dc20a302Sas200622 /*
2025dc20a302Sas200622  * Converts a multibyte character to a little-endian, wide-char, which
2026dc20a302Sas200622  * is stored in wcharp.  Up to nbytes bytes are examined.
2027dc20a302Sas200622  *
2028dc20a302Sas200622  * If mbchar is valid, returns the number of bytes processed in mbchar.
2029bbf6f00cSJordan Brown  * If mbchar is invalid, returns -1.  See also smb_mbtowc().
2030dc20a302Sas200622  */
2031dc20a302Sas200622 /*ARGSUSED*/
2032dc20a302Sas200622 int
2033bbf6f00cSJordan Brown ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar,
20348d7e4166Sjose borrego     size_t nbytes)
2035dc20a302Sas200622 {
2036dc20a302Sas200622 	int rc;
2037dc20a302Sas200622 
2038bbf6f00cSJordan Brown 	if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0)
2039dc20a302Sas200622 		return (rc);
2040dc20a302Sas200622 
2041dc20a302Sas200622 #ifdef _BIG_ENDIAN
20428d7e4166Sjose borrego 	if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND))
2043dc20a302Sas200622 		*wcharp = BSWAP_16(*wcharp);
2044dc20a302Sas200622 #endif
2045dc20a302Sas200622 
2046dc20a302Sas200622 	return (rc);
2047dc20a302Sas200622 }
2048