xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c (revision 5772:237ac22142fe)
1*5772Sas200622 /*
2*5772Sas200622  * CDDL HEADER START
3*5772Sas200622  *
4*5772Sas200622  * The contents of this file are subject to the terms of the
5*5772Sas200622  * Common Development and Distribution License (the "License").
6*5772Sas200622  * You may not use this file except in compliance with the License.
7*5772Sas200622  *
8*5772Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5772Sas200622  * or http://www.opensolaris.org/os/licensing.
10*5772Sas200622  * See the License for the specific language governing permissions
11*5772Sas200622  * and limitations under the License.
12*5772Sas200622  *
13*5772Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
14*5772Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5772Sas200622  * If applicable, add the following below this CDDL HEADER, with the
16*5772Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
17*5772Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5772Sas200622  *
19*5772Sas200622  * CDDL HEADER END
20*5772Sas200622  */
21*5772Sas200622 /*
22*5772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*5772Sas200622  * Use is subject to license terms.
24*5772Sas200622  */
25*5772Sas200622 
26*5772Sas200622 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5772Sas200622 
28*5772Sas200622 /*
29*5772Sas200622  * Network Data Representation (NDR) is a compatible subset of the DCE RPC
30*5772Sas200622  * and MSRPC NDR.  NDR is used to move parameters consisting of
31*5772Sas200622  * complicated trees of data constructs between an RPC client and server.
32*5772Sas200622  */
33*5772Sas200622 
34*5772Sas200622 #include <sys/byteorder.h>
35*5772Sas200622 #include <strings.h>
36*5772Sas200622 #include <assert.h>
37*5772Sas200622 #include <string.h>
38*5772Sas200622 #include <stdlib.h>
39*5772Sas200622 
40*5772Sas200622 #include <smbsrv/libsmb.h>
41*5772Sas200622 #include <smbsrv/string.h>
42*5772Sas200622 #include <smbsrv/ndr.h>
43*5772Sas200622 
44*5772Sas200622 #define	NDR_STRING_MAX		256
45*5772Sas200622 
46*5772Sas200622 #define	NDR_IS_UNION(T)	\
47*5772Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
48*5772Sas200622 #define	NDR_IS_STRING(T)	\
49*5772Sas200622 	(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
50*5772Sas200622 
51*5772Sas200622 extern struct ndr_typeinfo ndt_s_wchar;
52*5772Sas200622 
53*5772Sas200622 /*
54*5772Sas200622  * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
55*5772Sas200622  *
56*5772Sas200622  * Each parameter (call arguments and return values) is a TOP-MOST item.
57*5772Sas200622  * A TOP-MOST item consists of one or more OUTER items.  An OUTER item
58*5772Sas200622  * consists of one or more INNER items.  There are important differences
59*5772Sas200622  * between each kind, which, primarily, have to do with the allocation
60*5772Sas200622  * of memory to contain data structures and the order of processing.
61*5772Sas200622  *
62*5772Sas200622  * This is most easily demonstrated with a short example.
63*5772Sas200622  * Consider these structures:
64*5772Sas200622  *
65*5772Sas200622  *	struct top_param {
66*5772Sas200622  *		long		level;
67*5772Sas200622  *		struct list *	head;
68*5772Sas200622  *		long		count;
69*5772Sas200622  *	};
70*5772Sas200622  *
71*5772Sas200622  *	struct list {
72*5772Sas200622  *		struct list *	next;
73*5772Sas200622  *		char *		str; // a string
74*5772Sas200622  *	};
75*5772Sas200622  *
76*5772Sas200622  * Now, consider an instance tree like this:
77*5772Sas200622  *
78*5772Sas200622  *	+---------+       +-------+       +-------+
79*5772Sas200622  *	|top_param|  +--->|list #1|  +--->|list #2|
80*5772Sas200622  *	+---------+  |    +-------+  |    +-------+
81*5772Sas200622  *	| level   |  |    | next ----+    | next --->(NULL)
82*5772Sas200622  *	| head   ----+    | str  -->"foo" | str  -->"bar"
83*5772Sas200622  *	| count   |       | flag  |       | flag  |
84*5772Sas200622  *	+---------+       +-------+       +-------+
85*5772Sas200622  *
86*5772Sas200622  * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
87*5772Sas200622  * The vertical bars (|) indicate OUTER construct boundaries.
88*5772Sas200622  *
89*5772Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
90*5772Sas200622  *   |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
91*5772Sas200622  *   +-----+----------------------+----------------------+-----+-----+-----+
92*5772Sas200622  *   level |<----------------------- head -------------------------->|count
93*5772Sas200622  *   TOP    TOP                                                       TOP
94*5772Sas200622  *
95*5772Sas200622  * Here's what to notice:
96*5772Sas200622  *
97*5772Sas200622  * - The members of the TOP-MOST construct are scattered through the Stub
98*5772Sas200622  *   Data in the order they occur.  This example shows a TOP-MOST construct
99*5772Sas200622  *   consisting of atomic types (pointers and integers).  A construct
100*5772Sas200622  *   (struct) within the TOP-MOST construct would be contiguous and not
101*5772Sas200622  *   scattered.
102*5772Sas200622  *
103*5772Sas200622  * - The members of OUTER constructs are contiguous, which allows for
104*5772Sas200622  *   non-copied relocated (fixed-up) data structures at the packet's
105*5772Sas200622  *   destination.  We don't do fix-ups here.  The pointers within the
106*5772Sas200622  *   OUTER constructs are processed depth-first in the order that they
107*5772Sas200622  *   occur.  If they were processed breadth first, the sequence would
108*5772Sas200622  *   be #1,"foo",#2,"bar".  This is tricky because OUTER constructs may
109*5772Sas200622  *   be variable length, and pointers are often encountered before the
110*5772Sas200622  *   size(s) is known.
111*5772Sas200622  *
112*5772Sas200622  * - The INNER constructs are simply the members of an OUTER construct.
113*5772Sas200622  *
114*5772Sas200622  * For comparison, consider how ONC RPC would handle the same tree of
115*5772Sas200622  * data.  ONC requires very little buffering, while DCE requires enough
116*5772Sas200622  * buffer space for the entire message.  ONC does atom-by-atom depth-first
117*5772Sas200622  * (de)serialization and copy, while DCE allows for constructs to be
118*5772Sas200622  * "fixed-up" (relocated) in place at the destination.  The packet data
119*5772Sas200622  * for the same tree processed by ONC RPC would look like this:
120*5772Sas200622  *
121*5772Sas200622  *   +---------------------------------------------------------------------+
122*5772Sas200622  *   |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
123*5772Sas200622  *   +---------------------------------------------------------------------+
124*5772Sas200622  *   TOP    #1      #2      #2     bar   #2      #1     foo   #1      TOP
125*5772Sas200622  *
126*5772Sas200622  * More details about each TOP-MOST, OUTER, and INNER constructs appear
127*5772Sas200622  * throughout this source file near where such constructs are processed.
128*5772Sas200622  *
129*5772Sas200622  * NDR_REFERENCE
130*5772Sas200622  *
131*5772Sas200622  * The primary object for NDR is the struct ndr_reference.
132*5772Sas200622  *
133*5772Sas200622  * An ndr_reference indicates the local datum (i.e. native "C" data
134*5772Sas200622  * format), and the element within the Stub Data (contained within the
135*5772Sas200622  * RPC PDU (protocol data unit).  An ndr_reference also indicates,
136*5772Sas200622  * largely as a debugging aid, something about the type of the
137*5772Sas200622  * element/datum, and the enclosing construct for the element. The
138*5772Sas200622  * ndr_reference's are typically allocated on the stack as locals,
139*5772Sas200622  * and the chain of ndr_reference.enclosing references is in reverse
140*5772Sas200622  * order of the call graph.
141*5772Sas200622  *
142*5772Sas200622  * The ndr_reference.datum is a pointer to the local memory that
143*5772Sas200622  * contains/receives the value. The ndr_reference.pdu_offset indicates
144*5772Sas200622  * where in the Stub Data the value is to be stored/retrieved.
145*5772Sas200622  *
146*5772Sas200622  * The ndr_reference also contains various parameters to the NDR
147*5772Sas200622  * process, such as ndr_reference.size_is, which indicates the size
148*5772Sas200622  * of variable length data, or ndr_reference.switch_is, which
149*5772Sas200622  * indicates the arm of a union to use.
150*5772Sas200622  *
151*5772Sas200622  * QUEUE OF OUTER REFERENCES
152*5772Sas200622  *
153*5772Sas200622  * Some OUTER constructs are variable size.  Sometimes (often) we don't
154*5772Sas200622  * know the size of the OUTER construct until after pointers have been
155*5772Sas200622  * encountered. Hence, we can not begin processing the referent of the
156*5772Sas200622  * pointer until after the referring OUTER construct is completely
157*5772Sas200622  * processed, i.e. we don't know where to find/put the referent in the
158*5772Sas200622  * Stub Data until we know the size of all its predecessors.
159*5772Sas200622  *
160*5772Sas200622  * This is managed using the queue of OUTER references.  The queue is
161*5772Sas200622  * anchored in mlndr_stream.outer_queue_head.  At any time,
162*5772Sas200622  * mlndr_stream.outer_queue_tailp indicates where to put the
163*5772Sas200622  * ndr_reference for the next encountered pointer.
164*5772Sas200622  *
165*5772Sas200622  * Refer to the example above as we illustrate the queue here.  In these
166*5772Sas200622  * illustrations, the queue entries are not the data structures themselves.
167*5772Sas200622  * Rather, they are ndr_reference entries which **refer** to the data
168*5772Sas200622  * structures in both the PDU and local memory.
169*5772Sas200622  *
170*5772Sas200622  * During some point in the processing, the queue looks like this:
171*5772Sas200622  *
172*5772Sas200622  *   outer_current -------v
173*5772Sas200622  *   outer_queue_head --> list#1 --0
174*5772Sas200622  *   outer_queue_tailp ---------&
175*5772Sas200622  *
176*5772Sas200622  * When the pointer #1.next is encountered, and entry is added to the
177*5772Sas200622  * queue,
178*5772Sas200622  *
179*5772Sas200622  *   outer_current -------v
180*5772Sas200622  *   outer_queue_head --> list#1 --> list#2 --0
181*5772Sas200622  *   outer_queue_tailp --------------------&
182*5772Sas200622  *
183*5772Sas200622  * and the members of #1 continue to be processed, which encounters
184*5772Sas200622  * #1.str:
185*5772Sas200622  *
186*5772Sas200622  *   outer_current -------v
187*5772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
188*5772Sas200622  *   outer_queue_tailp ------------------------------&
189*5772Sas200622  *
190*5772Sas200622  * Upon the completion of list#1, the processing continues by moving
191*5772Sas200622  * to mlndr_stream.outer_current->next, and the tail is set to this
192*5772Sas200622  * outer member:
193*5772Sas200622  *
194*5772Sas200622  *   outer_current ------------------v
195*5772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "foo" --0
196*5772Sas200622  *   outer_queue_tailp --------------------&
197*5772Sas200622  *
198*5772Sas200622  * Space for list#2 is allocated, either in the Stub Data or of local
199*5772Sas200622  * memory.  When #2.next is encountered, it is found to be the null
200*5772Sas200622  * pointer and no reference is added to the queue.  When #2.str is
201*5772Sas200622  * encountered, it is found to be valid, and a reference is added:
202*5772Sas200622  *
203*5772Sas200622  *   outer_current ------------------v
204*5772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
205*5772Sas200622  *   outer_queue_tailp ------------------------------&
206*5772Sas200622  *
207*5772Sas200622  * Processing continues in a similar fashion with the string "bar",
208*5772Sas200622  * which is variable-length.  At this point, memory for "bar" may be
209*5772Sas200622  * malloc()ed during NDR_M_OP_UNMARSHALL:
210*5772Sas200622  *
211*5772Sas200622  *   outer_current -----------------------------v
212*5772Sas200622  *   outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
213*5772Sas200622  *   outer_queue_tailp ------------------------------&
214*5772Sas200622  *
215*5772Sas200622  * And finishes on string "foo".  Notice that because "bar" is a
216*5772Sas200622  * variable length string, and we don't know the PDU offset for "foo"
217*5772Sas200622  * until we reach this point.
218*5772Sas200622  *
219*5772Sas200622  * When the queue is drained (current->next==0), processing continues
220*5772Sas200622  * with the next TOP-MOST member.
221*5772Sas200622  *
222*5772Sas200622  * The queue of OUTER constructs manages the variable-length semantics
223*5772Sas200622  * of OUTER constructs and satisfies the depth-first requirement.
224*5772Sas200622  * We allow the queue to linger until the entire TOP-MOST structure is
225*5772Sas200622  * processed as an aid to debugging.
226*5772Sas200622  */
227*5772Sas200622 
228*5772Sas200622 static struct ndr_reference *mlndr_enter_outer_queue(struct ndr_reference *);
229*5772Sas200622 extern int mlndr__ulong(struct ndr_reference *);
230*5772Sas200622 
231*5772Sas200622 /*
232*5772Sas200622  * TOP-MOST ELEMENTS
233*5772Sas200622  *
234*5772Sas200622  * This is fundamentally the first OUTER construct of the parameter,
235*5772Sas200622  * possibly followed by more OUTER constructs due to pointers.  The
236*5772Sas200622  * datum (local memory) for TOP-MOST constructs (structs) is allocated
237*5772Sas200622  * by the caller of NDR.
238*5772Sas200622  *
239*5772Sas200622  * After the element is transferred, the outer_queue is drained.
240*5772Sas200622  *
241*5772Sas200622  * All we have to do is add an entry to the outer_queue for this
242*5772Sas200622  * top-most member, and commence the outer_queue processing.
243*5772Sas200622  */
244*5772Sas200622 int
245*5772Sas200622 mlndo_process(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
246*5772Sas200622     char *datum)
247*5772Sas200622 {
248*5772Sas200622 	struct ndr_reference	myref;
249*5772Sas200622 
250*5772Sas200622 	bzero(&myref, sizeof (myref));
251*5772Sas200622 	myref.stream = mlnds;
252*5772Sas200622 	myref.datum = datum;
253*5772Sas200622 	myref.name = "PROCESS";
254*5772Sas200622 	myref.ti = ti;
255*5772Sas200622 
256*5772Sas200622 	return (mlndr_topmost(&myref));
257*5772Sas200622 }
258*5772Sas200622 
259*5772Sas200622 int
260*5772Sas200622 mlndo_operation(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
261*5772Sas200622     int opnum, char *datum)
262*5772Sas200622 {
263*5772Sas200622 	struct ndr_reference	myref;
264*5772Sas200622 
265*5772Sas200622 	bzero(&myref, sizeof (myref));
266*5772Sas200622 	myref.stream = mlnds;
267*5772Sas200622 	myref.datum = datum;
268*5772Sas200622 	myref.name = "OPERATION";
269*5772Sas200622 	myref.ti = ti;
270*5772Sas200622 	myref.inner_flags = NDR_F_SWITCH_IS;
271*5772Sas200622 	myref.switch_is = opnum;
272*5772Sas200622 
273*5772Sas200622 	if (ti->type_flags != NDR_F_INTERFACE) {
274*5772Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
275*5772Sas200622 		return (0);
276*5772Sas200622 	}
277*5772Sas200622 
278*5772Sas200622 	return ((*ti->ndr_func)(&myref));
279*5772Sas200622 }
280*5772Sas200622 
281*5772Sas200622 int
282*5772Sas200622 mlndr_params(struct ndr_reference *params_ref)
283*5772Sas200622 {
284*5772Sas200622 	struct ndr_typeinfo *ti = params_ref->ti;
285*5772Sas200622 
286*5772Sas200622 	if (ti->type_flags == NDR_F_OPERATION)
287*5772Sas200622 		return (*ti->ndr_func) (params_ref);
288*5772Sas200622 	else
289*5772Sas200622 		return (mlndr_topmost(params_ref));
290*5772Sas200622 }
291*5772Sas200622 
292*5772Sas200622 int
293*5772Sas200622 mlndr_topmost(struct ndr_reference *top_ref)
294*5772Sas200622 {
295*5772Sas200622 	struct mlndr_stream *mlnds;
296*5772Sas200622 	struct ndr_typeinfo *ti;
297*5772Sas200622 	struct ndr_reference *outer_ref = 0;
298*5772Sas200622 	int	is_varlen;
299*5772Sas200622 	int	is_string;
300*5772Sas200622 	int	error;
301*5772Sas200622 	int	rc;
302*5772Sas200622 	unsigned n_fixed;
303*5772Sas200622 	int	params;
304*5772Sas200622 
305*5772Sas200622 	assert(top_ref);
306*5772Sas200622 	assert(top_ref->stream);
307*5772Sas200622 	assert(top_ref->ti);
308*5772Sas200622 
309*5772Sas200622 	mlnds = top_ref->stream;
310*5772Sas200622 	ti = top_ref->ti;
311*5772Sas200622 
312*5772Sas200622 	is_varlen = ti->pdu_size_variable_part;
313*5772Sas200622 	is_string = NDR_IS_STRING(ti);
314*5772Sas200622 
315*5772Sas200622 	assert(mlnds->outer_queue_tailp && !*mlnds->outer_queue_tailp);
316*5772Sas200622 	assert(!mlnds->outer_current);
317*5772Sas200622 
318*5772Sas200622 	params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
319*5772Sas200622 
320*5772Sas200622 	switch (params) {
321*5772Sas200622 	case NDR_F_NONE:
322*5772Sas200622 	case NDR_F_SWITCH_IS:
323*5772Sas200622 		if (is_string || is_varlen) {
324*5772Sas200622 			error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
325*5772Sas200622 			NDR_SET_ERROR(outer_ref, error);
326*5772Sas200622 			return (0);
327*5772Sas200622 		}
328*5772Sas200622 		n_fixed = ti->pdu_size_fixed_part;
329*5772Sas200622 		break;
330*5772Sas200622 
331*5772Sas200622 	case NDR_F_SIZE_IS:
332*5772Sas200622 		error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
333*5772Sas200622 		NDR_SET_ERROR(outer_ref, error);
334*5772Sas200622 		return (0);
335*5772Sas200622 
336*5772Sas200622 	case NDR_F_DIMENSION_IS:
337*5772Sas200622 		if (is_varlen) {
338*5772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
339*5772Sas200622 			NDR_SET_ERROR(outer_ref, error);
340*5772Sas200622 			return (0);
341*5772Sas200622 		}
342*5772Sas200622 		n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
343*5772Sas200622 		break;
344*5772Sas200622 
345*5772Sas200622 	case NDR_F_IS_POINTER:
346*5772Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
347*5772Sas200622 		n_fixed = 4;
348*5772Sas200622 		break;
349*5772Sas200622 
350*5772Sas200622 	case NDR_F_IS_REFERENCE:
351*5772Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
352*5772Sas200622 		n_fixed = 0;
353*5772Sas200622 		break;
354*5772Sas200622 
355*5772Sas200622 	default:
356*5772Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
357*5772Sas200622 		NDR_SET_ERROR(outer_ref, error);
358*5772Sas200622 		return (0);
359*5772Sas200622 	}
360*5772Sas200622 
361*5772Sas200622 	outer_ref = mlndr_enter_outer_queue(top_ref);
362*5772Sas200622 	if (!outer_ref)
363*5772Sas200622 		return (0);	/* error already set */
364*5772Sas200622 
365*5772Sas200622 	/*
366*5772Sas200622 	 * Hand-craft the first OUTER construct and directly call
367*5772Sas200622 	 * mlndr_inner(). Then, run the outer_queue. We do this
368*5772Sas200622 	 * because mlndr_outer() wants to malloc() memory for
369*5772Sas200622 	 * the construct, and we already have the memory.
370*5772Sas200622 	 */
371*5772Sas200622 
372*5772Sas200622 	/* move the flags, etc, around again, undoes enter_outer_queue() */
373*5772Sas200622 	outer_ref->inner_flags = top_ref->inner_flags;
374*5772Sas200622 	outer_ref->outer_flags = 0;
375*5772Sas200622 	outer_ref->datum = top_ref->datum;
376*5772Sas200622 
377*5772Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
378*5772Sas200622 	if (!mlndr_outer_align(outer_ref))
379*5772Sas200622 		return (0);		/* error already set */
380*5772Sas200622 
381*5772Sas200622 	/* Regardless of what it is, this is where it starts */
382*5772Sas200622 	outer_ref->pdu_offset = mlnds->pdu_scan_offset;
383*5772Sas200622 
384*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_fixed);
385*5772Sas200622 	if (!rc)
386*5772Sas200622 		return (0);		/* error already set */
387*5772Sas200622 
388*5772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
389*5772Sas200622 
390*5772Sas200622 	/* set-up outer_current, as though run_outer_queue() was doing it */
391*5772Sas200622 	mlnds->outer_current = outer_ref;
392*5772Sas200622 	mlnds->outer_queue_tailp = &mlnds->outer_current->next;
393*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
394*5772Sas200622 
395*5772Sas200622 	/* do the topmost member */
396*5772Sas200622 	rc = mlndr_inner(outer_ref);
397*5772Sas200622 	if (!rc)
398*5772Sas200622 		return (0);		/* error already set */
399*5772Sas200622 
400*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
401*5772Sas200622 
402*5772Sas200622 	/* advance, as though run_outer_queue() was doing it */
403*5772Sas200622 	mlnds->outer_current = mlnds->outer_current->next;
404*5772Sas200622 	return (mlndr_run_outer_queue(mlnds));
405*5772Sas200622 }
406*5772Sas200622 
407*5772Sas200622 static struct ndr_reference *
408*5772Sas200622 mlndr_enter_outer_queue(struct ndr_reference *arg_ref)
409*5772Sas200622 {
410*5772Sas200622 	struct mlndr_stream	*mlnds = arg_ref->stream;
411*5772Sas200622 	struct ndr_reference	*outer_ref;
412*5772Sas200622 
413*5772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
414*5772Sas200622 	outer_ref = (struct ndr_reference *)
415*5772Sas200622 	    MLNDS_MALLOC(mlnds, sizeof (*outer_ref), arg_ref);
416*5772Sas200622 	if (!outer_ref) {
417*5772Sas200622 		NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
418*5772Sas200622 		return (0);
419*5772Sas200622 	}
420*5772Sas200622 
421*5772Sas200622 	*outer_ref = *arg_ref;
422*5772Sas200622 
423*5772Sas200622 	/* move advice in inner_flags to outer_flags */
424*5772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
425*5772Sas200622 	outer_ref->inner_flags = 0;
426*5772Sas200622 	outer_ref->enclosing = mlnds->outer_current;
427*5772Sas200622 	outer_ref->backptr = 0;
428*5772Sas200622 	outer_ref->datum = 0;
429*5772Sas200622 
430*5772Sas200622 	assert(mlnds->outer_queue_tailp);
431*5772Sas200622 
432*5772Sas200622 	outer_ref->next = *mlnds->outer_queue_tailp;
433*5772Sas200622 	*mlnds->outer_queue_tailp = outer_ref;
434*5772Sas200622 	mlnds->outer_queue_tailp = &outer_ref->next;
435*5772Sas200622 	return (outer_ref);
436*5772Sas200622 }
437*5772Sas200622 
438*5772Sas200622 int
439*5772Sas200622 mlndr_run_outer_queue(struct mlndr_stream *mlnds)
440*5772Sas200622 {
441*5772Sas200622 	while (mlnds->outer_current) {
442*5772Sas200622 		mlnds->outer_queue_tailp = &mlnds->outer_current->next;
443*5772Sas200622 
444*5772Sas200622 		if (!mlndr_outer(mlnds->outer_current))
445*5772Sas200622 			return (0);
446*5772Sas200622 
447*5772Sas200622 		mlnds->outer_current = mlnds->outer_current->next;
448*5772Sas200622 	}
449*5772Sas200622 
450*5772Sas200622 	return (1);
451*5772Sas200622 }
452*5772Sas200622 
453*5772Sas200622 /*
454*5772Sas200622  * OUTER CONSTRUCTS
455*5772Sas200622  *
456*5772Sas200622  * OUTER constructs are where the real work is, which stems from the
457*5772Sas200622  * variable-length potential.
458*5772Sas200622  *
459*5772Sas200622  * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
460*5772Sas200622  *
461*5772Sas200622  * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
462*5772Sas200622  * VARYING, and VARYING/CONFORMANT.
463*5772Sas200622  *
464*5772Sas200622  * What makes this so tough is that the variable-length array may be well
465*5772Sas200622  * encapsulated within the outer construct.  Further, because DCE(MS)/RPC
466*5772Sas200622  * tries to keep the constructs contiguous in the data stream, the sizing
467*5772Sas200622  * information precedes the entire OUTER construct.  The sizing information
468*5772Sas200622  * must be used at the appropriate time, which can be after many, many,
469*5772Sas200622  * many fixed-length elements.  During IDL type analysis, we know in
470*5772Sas200622  * advance constructs that encapsulate variable-length constructs.  So,
471*5772Sas200622  * we know when we have a sizing header and when we don't.  The actual
472*5772Sas200622  * semantics of the header are largely deferred.
473*5772Sas200622  *
474*5772Sas200622  * Currently, VARYING constructs are not implemented but they are described
475*5772Sas200622  * here in case they have to be implemented in the future.  Similarly,
476*5772Sas200622  * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
477*5772Sas200622  * not implemented.  Only one-dimensional, variable-length arrays are
478*5772Sas200622  * supported.
479*5772Sas200622  *
480*5772Sas200622  * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
481*5772Sas200622  *
482*5772Sas200622  * All variable-length values are arrays.  These arrays may be embedded
483*5772Sas200622  * well within another construct.  However, a variable-length construct
484*5772Sas200622  * may ONLY appear as the last member of an enclosing construct.  Example:
485*5772Sas200622  *
486*5772Sas200622  *	struct credentials {
487*5772Sas200622  *		ulong	uid, gid;
488*5772Sas200622  *		ulong	n_gids;
489*5772Sas200622  *	    [size_is(n_gids)]
490*5772Sas200622  *		ulong	gids[*];    // variable-length.
491*5772Sas200622  *	};
492*5772Sas200622  *
493*5772Sas200622  * CONFORMANT constructs have a dynamic size in local memory and in the
494*5772Sas200622  * PDU.  The CONFORMANT quality is indicated by the [size_is()] advice.
495*5772Sas200622  * CONFORMANT constructs have the following header:
496*5772Sas200622  *
497*5772Sas200622  *	struct conformant_header {
498*5772Sas200622  *		ulong		size_is;
499*5772Sas200622  *	};
500*5772Sas200622  *
501*5772Sas200622  * (Multi-dimensional CONFORMANT arrays have a similar header for each
502*5772Sas200622  * dimension - not implemented).
503*5772Sas200622  *
504*5772Sas200622  * Example CONFORMANT construct:
505*5772Sas200622  *
506*5772Sas200622  *	struct user {
507*5772Sas200622  *		char *			name;
508*5772Sas200622  *		struct credentials	cred;	// see above
509*5772Sas200622  *	};
510*5772Sas200622  *
511*5772Sas200622  * Consider the data tree:
512*5772Sas200622  *
513*5772Sas200622  *    +--------+
514*5772Sas200622  *    |  user  |
515*5772Sas200622  *    +--------+
516*5772Sas200622  *    | name  ----> "fred" (the string is a different OUTER)
517*5772Sas200622  *    | uid    |
518*5772Sas200622  *    | gid    |
519*5772Sas200622  *    | n_gids |    for example, 3
520*5772Sas200622  *    | gids[0]|
521*5772Sas200622  *    | gids[1]|
522*5772Sas200622  *    | gids[2]|
523*5772Sas200622  *    +--------+
524*5772Sas200622  *
525*5772Sas200622  * The OUTER construct in the Stub Data would be:
526*5772Sas200622  *
527*5772Sas200622  *    +---+---------+---------------------------------------------+
528*5772Sas200622  *    |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
529*5772Sas200622  *    +---+---------+---------------------------------------------+
530*5772Sas200622  *         szing hdr|user |<-------------- user.cred ------------>|
531*5772Sas200622  *                  |<--- fixed-size ---->|<----- conformant ---->|
532*5772Sas200622  *
533*5772Sas200622  * The ndr_typeinfo for struct user will have:
534*5772Sas200622  *	pdu_fixed_size_part = 16	four long words (name uid gid n_gids)
535*5772Sas200622  *	pdu_variable_size_part = 4	per element, sizeof gids[0]
536*5772Sas200622  *
537*5772Sas200622  * VARYING CONSTRUCTS -- NOT IMPLEMENTED
538*5772Sas200622  *
539*5772Sas200622  * VARYING constructs have the following header:
540*5772Sas200622  *
541*5772Sas200622  *	struct varying_header {
542*5772Sas200622  *		ulong		first_is;
543*5772Sas200622  *		ulong		length_is;
544*5772Sas200622  *	};
545*5772Sas200622  *
546*5772Sas200622  * This indicates which interval of an array is significant.
547*5772Sas200622  * Non-intersecting elements of the array are undefined and usually
548*5772Sas200622  * zero-filled.  The first_is parameter for C arrays is always 0 for
549*5772Sas200622  * the first element.
550*5772Sas200622  *
551*5772Sas200622  * N.B. Constructs may contain one CONFORMANT element, which is always
552*5772Sas200622  * last, but may contain many VARYING elements, which can be anywhere.
553*5772Sas200622  *
554*5772Sas200622  * VARYING CONFORMANT constructs have the sizing headers arranged like
555*5772Sas200622  * this:
556*5772Sas200622  *
557*5772Sas200622  *	struct conformant_header	all_conformant[N_CONFORMANT_DIM];
558*5772Sas200622  *	struct varying_header		all_varying[N_VARYING_ELEMS_AND_DIMS];
559*5772Sas200622  *
560*5772Sas200622  * The sizing header is immediately followed by the values for the
561*5772Sas200622  * construct.  Again, we don't support more than one dimension and
562*5772Sas200622  * we don't support VARYING constructs at this time.
563*5772Sas200622  *
564*5772Sas200622  * A good example of a VARYING/CONFORMANT data structure is the UNIX
565*5772Sas200622  * directory entry:
566*5772Sas200622  *
567*5772Sas200622  *	struct dirent {
568*5772Sas200622  *		ushort		reclen;
569*5772Sas200622  *		ushort		namlen;
570*5772Sas200622  *		ulong		inum;
571*5772Sas200622  *	    [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
572*5772Sas200622  *		uchar		name[*];
573*5772Sas200622  *	};
574*5772Sas200622  *
575*5772Sas200622  *
576*5772Sas200622  * STRINGS ARE A SPECIAL CASE
577*5772Sas200622  *
578*5772Sas200622  * Strings are handled specially.  MS/RPC uses VARYING/CONFORMANT structures
579*5772Sas200622  * for strings.  This is a simple one-dimensional variable-length array,
580*5772Sas200622  * typically with its last element all zeroes.  We handle strings with the
581*5772Sas200622  * header:
582*5772Sas200622  *
583*5772Sas200622  *	struct string_header {
584*5772Sas200622  *		ulong		size_is;
585*5772Sas200622  *		ulong		first_is;	// always 0
586*5772Sas200622  *		ulong		length_is;	// always same as size_is
587*5772Sas200622  *	};
588*5772Sas200622  *
589*5772Sas200622  * If general support for VARYING and VARYING/CONFORMANT mechanisms is
590*5772Sas200622  * implemented, we probably won't need the strings special case.
591*5772Sas200622  */
592*5772Sas200622 int
593*5772Sas200622 mlndr_outer(struct ndr_reference *outer_ref)
594*5772Sas200622 {
595*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
596*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
597*5772Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
598*5772Sas200622 	int	is_union = NDR_IS_UNION(ti);
599*5772Sas200622 	int	is_string = NDR_IS_STRING(ti);
600*5772Sas200622 	int	error = NDR_ERR_OUTER_PARAMS_BAD;
601*5772Sas200622 	int	params;
602*5772Sas200622 
603*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
604*5772Sas200622 
605*5772Sas200622 	NDR_TATTLE(outer_ref, "--OUTER--");
606*5772Sas200622 
607*5772Sas200622 	/* All outer constructs start on a mod4 (longword) boundary */
608*5772Sas200622 	if (!mlndr_outer_align(outer_ref))
609*5772Sas200622 		return (0);		/* error already set */
610*5772Sas200622 
611*5772Sas200622 	/* Regardless of what it is, this is where it starts */
612*5772Sas200622 	outer_ref->pdu_offset = mlnds->pdu_scan_offset;
613*5772Sas200622 
614*5772Sas200622 	if (is_union) {
615*5772Sas200622 		error = NDR_ERR_OUTER_UNION_ILLEGAL;
616*5772Sas200622 		NDR_SET_ERROR(outer_ref, error);
617*5772Sas200622 		return (0);
618*5772Sas200622 	}
619*5772Sas200622 
620*5772Sas200622 	switch (params) {
621*5772Sas200622 	case NDR_F_NONE:
622*5772Sas200622 		if (is_string)
623*5772Sas200622 			return (mlndr_outer_string(outer_ref));
624*5772Sas200622 		if (is_varlen)
625*5772Sas200622 			return (mlndr_outer_conformant_construct(outer_ref));
626*5772Sas200622 
627*5772Sas200622 		return (mlndr_outer_fixed(outer_ref));
628*5772Sas200622 		break;
629*5772Sas200622 
630*5772Sas200622 	case NDR_F_SIZE_IS:
631*5772Sas200622 	case NDR_F_DIMENSION_IS:
632*5772Sas200622 		if (is_varlen) {
633*5772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
634*5772Sas200622 			break;
635*5772Sas200622 		}
636*5772Sas200622 
637*5772Sas200622 		if (params == NDR_F_SIZE_IS)
638*5772Sas200622 			return (mlndr_outer_conformant_array(outer_ref));
639*5772Sas200622 		else
640*5772Sas200622 			return (mlndr_outer_fixed_array(outer_ref));
641*5772Sas200622 		break;
642*5772Sas200622 
643*5772Sas200622 	default:
644*5772Sas200622 		error = NDR_ERR_OUTER_PARAMS_BAD;
645*5772Sas200622 		break;
646*5772Sas200622 	}
647*5772Sas200622 
648*5772Sas200622 	/*
649*5772Sas200622 	 * If we get here, something is wrong. Most likely,
650*5772Sas200622 	 * the params flags do not match.
651*5772Sas200622 	 */
652*5772Sas200622 	NDR_SET_ERROR(outer_ref, error);
653*5772Sas200622 	return (0);
654*5772Sas200622 }
655*5772Sas200622 
656*5772Sas200622 int
657*5772Sas200622 mlndr_outer_fixed(struct ndr_reference *outer_ref)
658*5772Sas200622 {
659*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
660*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
661*5772Sas200622 	struct ndr_reference	myref;
662*5772Sas200622 	char 		*valp = NULL;
663*5772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
664*5772Sas200622 	int		is_union = NDR_IS_UNION(ti);
665*5772Sas200622 	int		is_string = NDR_IS_STRING(ti);
666*5772Sas200622 	int		rc;
667*5772Sas200622 	unsigned	n_hdr;
668*5772Sas200622 	unsigned	n_fixed;
669*5772Sas200622 	unsigned	n_variable;
670*5772Sas200622 	unsigned	n_alloc;
671*5772Sas200622 	unsigned	n_pdu_total;
672*5772Sas200622 	int		params;
673*5772Sas200622 
674*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
675*5772Sas200622 
676*5772Sas200622 	assert(!is_varlen && !is_string && !is_union);
677*5772Sas200622 	assert(params == NDR_F_NONE);
678*5772Sas200622 
679*5772Sas200622 	/* no header for this */
680*5772Sas200622 	n_hdr = 0;
681*5772Sas200622 
682*5772Sas200622 	/* fixed part -- exactly one of these */
683*5772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
684*5772Sas200622 	assert(n_fixed > 0);
685*5772Sas200622 
686*5772Sas200622 	/* variable part -- exactly none of these */
687*5772Sas200622 	n_variable = 0;
688*5772Sas200622 
689*5772Sas200622 	/* sum them up to determine the PDU space required */
690*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
691*5772Sas200622 
692*5772Sas200622 	/* similar sum to determine how much local memory is required */
693*5772Sas200622 	n_alloc = n_fixed + n_variable;
694*5772Sas200622 
695*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
696*5772Sas200622 	if (!rc)
697*5772Sas200622 		return (rc);		/* error already set */
698*5772Sas200622 
699*5772Sas200622 	switch (mlnds->m_op) {
700*5772Sas200622 	case NDR_M_OP_MARSHALL:
701*5772Sas200622 		valp = outer_ref->datum;
702*5772Sas200622 		assert(valp);
703*5772Sas200622 		if (outer_ref->backptr) {
704*5772Sas200622 			assert(valp == *outer_ref->backptr);
705*5772Sas200622 		}
706*5772Sas200622 		break;
707*5772Sas200622 
708*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
709*5772Sas200622 		valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
710*5772Sas200622 		if (!valp) {
711*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
712*5772Sas200622 			return (0);
713*5772Sas200622 		}
714*5772Sas200622 		if (outer_ref->backptr)
715*5772Sas200622 			*outer_ref->backptr = valp;
716*5772Sas200622 		outer_ref->datum = valp;
717*5772Sas200622 		break;
718*5772Sas200622 
719*5772Sas200622 	default:
720*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
721*5772Sas200622 		return (0);
722*5772Sas200622 	}
723*5772Sas200622 
724*5772Sas200622 	bzero(&myref, sizeof (myref));
725*5772Sas200622 	myref.stream = mlnds;
726*5772Sas200622 	myref.enclosing = outer_ref;
727*5772Sas200622 	myref.ti = outer_ref->ti;
728*5772Sas200622 	myref.datum = outer_ref->datum;
729*5772Sas200622 	myref.name = "FIXED-VALUE";
730*5772Sas200622 	myref.outer_flags = NDR_F_NONE;
731*5772Sas200622 	myref.inner_flags = NDR_F_NONE;
732*5772Sas200622 
733*5772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
734*5772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
735*5772Sas200622 
736*5772Sas200622 	rc = mlndr_inner(&myref);
737*5772Sas200622 	if (!rc)
738*5772Sas200622 		return (rc);		/* error already set */
739*5772Sas200622 
740*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
741*5772Sas200622 	return (1);
742*5772Sas200622 }
743*5772Sas200622 
744*5772Sas200622 int
745*5772Sas200622 mlndr_outer_fixed_array(struct ndr_reference *outer_ref)
746*5772Sas200622 {
747*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
748*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
749*5772Sas200622 	struct ndr_reference	myref;
750*5772Sas200622 	char 		*valp = NULL;
751*5772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
752*5772Sas200622 	int		is_union = NDR_IS_UNION(ti);
753*5772Sas200622 	int		is_string = NDR_IS_STRING(ti);
754*5772Sas200622 	int		rc;
755*5772Sas200622 	unsigned	n_hdr;
756*5772Sas200622 	unsigned	n_fixed;
757*5772Sas200622 	unsigned	n_variable;
758*5772Sas200622 	unsigned	n_alloc;
759*5772Sas200622 	unsigned	n_pdu_total;
760*5772Sas200622 	int		params;
761*5772Sas200622 
762*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
763*5772Sas200622 
764*5772Sas200622 	assert(!is_varlen && !is_string && !is_union);
765*5772Sas200622 	assert(params == NDR_F_DIMENSION_IS);
766*5772Sas200622 
767*5772Sas200622 	/* no header for this */
768*5772Sas200622 	n_hdr = 0;
769*5772Sas200622 
770*5772Sas200622 	/* fixed part -- exactly dimension_is of these */
771*5772Sas200622 	n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
772*5772Sas200622 	assert(n_fixed > 0);
773*5772Sas200622 
774*5772Sas200622 	/* variable part -- exactly none of these */
775*5772Sas200622 	n_variable = 0;
776*5772Sas200622 
777*5772Sas200622 	/* sum them up to determine the PDU space required */
778*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
779*5772Sas200622 
780*5772Sas200622 	/* similar sum to determine how much local memory is required */
781*5772Sas200622 	n_alloc = n_fixed + n_variable;
782*5772Sas200622 
783*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
784*5772Sas200622 	if (!rc)
785*5772Sas200622 		return (rc);		/* error already set */
786*5772Sas200622 
787*5772Sas200622 	switch (mlnds->m_op) {
788*5772Sas200622 	case NDR_M_OP_MARSHALL:
789*5772Sas200622 		valp = outer_ref->datum;
790*5772Sas200622 		assert(valp);
791*5772Sas200622 		if (outer_ref->backptr) {
792*5772Sas200622 			assert(valp == *outer_ref->backptr);
793*5772Sas200622 		}
794*5772Sas200622 		break;
795*5772Sas200622 
796*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
797*5772Sas200622 		valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
798*5772Sas200622 		if (!valp) {
799*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
800*5772Sas200622 			return (0);
801*5772Sas200622 		}
802*5772Sas200622 		if (outer_ref->backptr)
803*5772Sas200622 			*outer_ref->backptr = valp;
804*5772Sas200622 		outer_ref->datum = valp;
805*5772Sas200622 		break;
806*5772Sas200622 
807*5772Sas200622 	default:
808*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
809*5772Sas200622 		return (0);
810*5772Sas200622 	}
811*5772Sas200622 
812*5772Sas200622 	bzero(&myref, sizeof (myref));
813*5772Sas200622 	myref.stream = mlnds;
814*5772Sas200622 	myref.enclosing = outer_ref;
815*5772Sas200622 	myref.ti = outer_ref->ti;
816*5772Sas200622 	myref.datum = outer_ref->datum;
817*5772Sas200622 	myref.name = "FIXED-ARRAY";
818*5772Sas200622 	myref.outer_flags = NDR_F_NONE;
819*5772Sas200622 	myref.inner_flags = NDR_F_DIMENSION_IS;
820*5772Sas200622 	myref.dimension_is = outer_ref->dimension_is;
821*5772Sas200622 
822*5772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset;
823*5772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
824*5772Sas200622 
825*5772Sas200622 	rc = mlndr_inner(&myref);
826*5772Sas200622 	if (!rc)
827*5772Sas200622 		return (rc);		/* error already set */
828*5772Sas200622 
829*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
830*5772Sas200622 	return (1);
831*5772Sas200622 }
832*5772Sas200622 
833*5772Sas200622 int
834*5772Sas200622 mlndr_outer_conformant_array(struct ndr_reference *outer_ref)
835*5772Sas200622 {
836*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
837*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
838*5772Sas200622 	struct ndr_reference	myref;
839*5772Sas200622 	char 		*valp = NULL;
840*5772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
841*5772Sas200622 	int		is_union = NDR_IS_UNION(ti);
842*5772Sas200622 	int		is_string = NDR_IS_STRING(ti);
843*5772Sas200622 	unsigned long	size_is;
844*5772Sas200622 	int		rc;
845*5772Sas200622 	unsigned	n_hdr;
846*5772Sas200622 	unsigned	n_fixed;
847*5772Sas200622 	unsigned	n_variable;
848*5772Sas200622 	unsigned	n_alloc;
849*5772Sas200622 	unsigned	n_pdu_total;
850*5772Sas200622 	int		params;
851*5772Sas200622 
852*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
853*5772Sas200622 
854*5772Sas200622 	assert(!is_varlen && !is_string && !is_union);
855*5772Sas200622 	assert(params == NDR_F_SIZE_IS);
856*5772Sas200622 
857*5772Sas200622 	/* conformant header for this */
858*5772Sas200622 	n_hdr = 4;
859*5772Sas200622 
860*5772Sas200622 	/* fixed part -- exactly none of these */
861*5772Sas200622 	n_fixed = 0;
862*5772Sas200622 
863*5772Sas200622 	/* variable part -- exactly size_of of these */
864*5772Sas200622 	/* notice that it is the **fixed** size of the ti */
865*5772Sas200622 	n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
866*5772Sas200622 
867*5772Sas200622 	/* sum them up to determine the PDU space required */
868*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
869*5772Sas200622 
870*5772Sas200622 	/* similar sum to determine how much local memory is required */
871*5772Sas200622 	n_alloc = n_fixed + n_variable;
872*5772Sas200622 
873*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
874*5772Sas200622 	if (!rc)
875*5772Sas200622 		return (rc);		/* error already set */
876*5772Sas200622 
877*5772Sas200622 	switch (mlnds->m_op) {
878*5772Sas200622 	case NDR_M_OP_MARSHALL:
879*5772Sas200622 		size_is = outer_ref->size_is;
880*5772Sas200622 		rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
881*5772Sas200622 		if (!rc)
882*5772Sas200622 			return (0);	/* error already set */
883*5772Sas200622 
884*5772Sas200622 		valp = outer_ref->datum;
885*5772Sas200622 		assert(valp);
886*5772Sas200622 		if (outer_ref->backptr) {
887*5772Sas200622 			assert(valp == *outer_ref->backptr);
888*5772Sas200622 		}
889*5772Sas200622 		break;
890*5772Sas200622 
891*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
892*5772Sas200622 		rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is);
893*5772Sas200622 		if (!rc)
894*5772Sas200622 			return (0);	/* error already set */
895*5772Sas200622 
896*5772Sas200622 		if (size_is != outer_ref->size_is) {
897*5772Sas200622 			NDR_SET_ERROR(outer_ref,
898*5772Sas200622 			    NDR_ERR_SIZE_IS_MISMATCH_PDU);
899*5772Sas200622 			return (0);
900*5772Sas200622 		}
901*5772Sas200622 
902*5772Sas200622 		valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
903*5772Sas200622 		if (!valp) {
904*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
905*5772Sas200622 			return (0);
906*5772Sas200622 		}
907*5772Sas200622 		if (outer_ref->backptr)
908*5772Sas200622 			*outer_ref->backptr = valp;
909*5772Sas200622 		outer_ref->datum = valp;
910*5772Sas200622 		break;
911*5772Sas200622 
912*5772Sas200622 	default:
913*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
914*5772Sas200622 		return (0);
915*5772Sas200622 	}
916*5772Sas200622 
917*5772Sas200622 	bzero(&myref, sizeof (myref));
918*5772Sas200622 	myref.stream = mlnds;
919*5772Sas200622 	myref.enclosing = outer_ref;
920*5772Sas200622 	myref.ti = outer_ref->ti;
921*5772Sas200622 	myref.datum = outer_ref->datum;
922*5772Sas200622 	myref.name = "CONFORMANT-ARRAY";
923*5772Sas200622 	myref.outer_flags = NDR_F_NONE;
924*5772Sas200622 	myref.inner_flags = NDR_F_SIZE_IS;
925*5772Sas200622 	myref.size_is = outer_ref->size_is;
926*5772Sas200622 
927*5772Sas200622 	myref.inner_flags = NDR_F_DIMENSION_IS;		/* convenient */
928*5772Sas200622 	myref.dimension_is = outer_ref->size_is;	/* convenient */
929*5772Sas200622 
930*5772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 4;
931*5772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
932*5772Sas200622 
933*5772Sas200622 	outer_ref->type_flags = NDR_F_NONE;
934*5772Sas200622 	outer_ref->inner_flags = NDR_F_NONE;
935*5772Sas200622 
936*5772Sas200622 	rc = mlndr_inner(&myref);
937*5772Sas200622 	if (!rc)
938*5772Sas200622 		return (rc);		/* error already set */
939*5772Sas200622 
940*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
941*5772Sas200622 	return (1);
942*5772Sas200622 }
943*5772Sas200622 
944*5772Sas200622 int
945*5772Sas200622 mlndr_outer_conformant_construct(struct ndr_reference *outer_ref)
946*5772Sas200622 {
947*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
948*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
949*5772Sas200622 	struct ndr_reference	myref;
950*5772Sas200622 	char 		*valp = NULL;
951*5772Sas200622 	int		is_varlen = ti->pdu_size_variable_part;
952*5772Sas200622 	int		is_union = NDR_IS_UNION(ti);
953*5772Sas200622 	int		is_string = NDR_IS_STRING(ti);
954*5772Sas200622 	unsigned long	size_is;
955*5772Sas200622 	int		rc;
956*5772Sas200622 	unsigned	n_hdr;
957*5772Sas200622 	unsigned	n_fixed;
958*5772Sas200622 	unsigned	n_variable;
959*5772Sas200622 	unsigned	n_alloc;
960*5772Sas200622 	unsigned	n_pdu_total;
961*5772Sas200622 	int		params;
962*5772Sas200622 
963*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
964*5772Sas200622 
965*5772Sas200622 	assert(is_varlen && !is_string && !is_union);
966*5772Sas200622 	assert(params == NDR_F_NONE);
967*5772Sas200622 
968*5772Sas200622 	/* conformant header for this */
969*5772Sas200622 	n_hdr = 4;
970*5772Sas200622 
971*5772Sas200622 	/* fixed part -- exactly one of these */
972*5772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
973*5772Sas200622 
974*5772Sas200622 	/* variable part -- exactly size_of of these */
975*5772Sas200622 	n_variable = 0;		/* 0 for the moment */
976*5772Sas200622 
977*5772Sas200622 	/* sum them up to determine the PDU space required */
978*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
979*5772Sas200622 
980*5772Sas200622 	/* similar sum to determine how much local memory is required */
981*5772Sas200622 	n_alloc = n_fixed + n_variable;
982*5772Sas200622 
983*5772Sas200622 	/* For the moment, grow enough for the fixed-size part */
984*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
985*5772Sas200622 	if (!rc)
986*5772Sas200622 		return (rc);		/* error already set */
987*5772Sas200622 
988*5772Sas200622 	switch (mlnds->m_op) {
989*5772Sas200622 	case NDR_M_OP_MARSHALL:
990*5772Sas200622 		/*
991*5772Sas200622 		 * We don't know the size yet. We have to wait for
992*5772Sas200622 		 * it. Proceed with the fixed-size part, and await
993*5772Sas200622 		 * the call to mlndr_size_is().
994*5772Sas200622 		 */
995*5772Sas200622 		size_is = 0;
996*5772Sas200622 		rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
997*5772Sas200622 		if (!rc)
998*5772Sas200622 			return (0);	/* error already set */
999*5772Sas200622 
1000*5772Sas200622 		valp = outer_ref->datum;
1001*5772Sas200622 		assert(valp);
1002*5772Sas200622 		if (outer_ref->backptr) {
1003*5772Sas200622 			assert(valp == *outer_ref->backptr);
1004*5772Sas200622 		}
1005*5772Sas200622 		break;
1006*5772Sas200622 
1007*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1008*5772Sas200622 		/*
1009*5772Sas200622 		 * We know the size of the variable part because
1010*5772Sas200622 		 * of the CONFORMANT header. We will verify
1011*5772Sas200622 		 * the header against the [size_is(X)] advice
1012*5772Sas200622 		 * later when mlndr_size_is() is called.
1013*5772Sas200622 		 */
1014*5772Sas200622 		rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is);
1015*5772Sas200622 		if (!rc)
1016*5772Sas200622 			return (0);	/* error already set */
1017*5772Sas200622 
1018*5772Sas200622 		/* recalculate metrics */
1019*5772Sas200622 		n_variable = size_is * ti->pdu_size_variable_part;
1020*5772Sas200622 		n_pdu_total = n_hdr + n_fixed + n_variable;
1021*5772Sas200622 		n_alloc = n_fixed + n_variable;
1022*5772Sas200622 
1023*5772Sas200622 		rc = mlndr_outer_grow(outer_ref, n_pdu_total);
1024*5772Sas200622 		if (!rc)
1025*5772Sas200622 			return (rc);		/* error already set */
1026*5772Sas200622 
1027*5772Sas200622 		outer_ref->size_is = size_is; /* verified later */
1028*5772Sas200622 
1029*5772Sas200622 		valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
1030*5772Sas200622 		if (!valp) {
1031*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1032*5772Sas200622 			return (0);
1033*5772Sas200622 		}
1034*5772Sas200622 		if (outer_ref->backptr)
1035*5772Sas200622 			*outer_ref->backptr = valp;
1036*5772Sas200622 		outer_ref->datum = valp;
1037*5772Sas200622 		break;
1038*5772Sas200622 
1039*5772Sas200622 	default:
1040*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1041*5772Sas200622 		return (0);
1042*5772Sas200622 	}
1043*5772Sas200622 
1044*5772Sas200622 	bzero(&myref, sizeof (myref));
1045*5772Sas200622 	myref.stream = mlnds;
1046*5772Sas200622 	myref.enclosing = outer_ref;
1047*5772Sas200622 	myref.ti = outer_ref->ti;
1048*5772Sas200622 	myref.datum = outer_ref->datum;
1049*5772Sas200622 	myref.name = "CONFORMANT-CONSTRUCT";
1050*5772Sas200622 	myref.outer_flags = NDR_F_NONE;
1051*5772Sas200622 	myref.inner_flags = NDR_F_NONE;
1052*5772Sas200622 	myref.size_is = outer_ref->size_is;
1053*5772Sas200622 
1054*5772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 4;
1055*5772Sas200622 	outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
1056*5772Sas200622 
1057*5772Sas200622 	outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
1058*5772Sas200622 	outer_ref->inner_flags = NDR_F_NONE;   /* indicate pending */
1059*5772Sas200622 
1060*5772Sas200622 	rc = mlndr_inner(&myref);
1061*5772Sas200622 	if (!rc)
1062*5772Sas200622 		return (rc);		/* error already set */
1063*5772Sas200622 
1064*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
1065*5772Sas200622 
1066*5772Sas200622 	if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
1067*5772Sas200622 		NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
1068*5772Sas200622 		return (0);
1069*5772Sas200622 	}
1070*5772Sas200622 
1071*5772Sas200622 	return (1);
1072*5772Sas200622 }
1073*5772Sas200622 
1074*5772Sas200622 int
1075*5772Sas200622 mlndr_size_is(struct ndr_reference *ref)
1076*5772Sas200622 {
1077*5772Sas200622 	struct mlndr_stream 	*mlnds = ref->stream;
1078*5772Sas200622 	struct ndr_reference 	*outer_ref = mlnds->outer_current;
1079*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
1080*5772Sas200622 	unsigned long		size_is;
1081*5772Sas200622 	int			rc;
1082*5772Sas200622 	unsigned		n_hdr;
1083*5772Sas200622 	unsigned		n_fixed;
1084*5772Sas200622 	unsigned		n_variable;
1085*5772Sas200622 	unsigned		n_pdu_total;
1086*5772Sas200622 
1087*5772Sas200622 	assert(ref->inner_flags & NDR_F_SIZE_IS);
1088*5772Sas200622 	size_is = ref->size_is;
1089*5772Sas200622 
1090*5772Sas200622 	if (outer_ref->type_flags != NDR_F_SIZE_IS) {
1091*5772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
1092*5772Sas200622 		return (0);
1093*5772Sas200622 	}
1094*5772Sas200622 
1095*5772Sas200622 	if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
1096*5772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
1097*5772Sas200622 		return (0);
1098*5772Sas200622 	}
1099*5772Sas200622 
1100*5772Sas200622 	/* repeat metrics, see mlndr_conformant_construct() above */
1101*5772Sas200622 	n_hdr = 4;
1102*5772Sas200622 	n_fixed = ti->pdu_size_fixed_part;
1103*5772Sas200622 	n_variable = size_is * ti->pdu_size_variable_part;
1104*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
1105*5772Sas200622 
1106*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
1107*5772Sas200622 	if (!rc)
1108*5772Sas200622 		return (rc);		/* error already set */
1109*5772Sas200622 
1110*5772Sas200622 	switch (mlnds->m_op) {
1111*5772Sas200622 	case NDR_M_OP_MARSHALL:
1112*5772Sas200622 		/*
1113*5772Sas200622 		 * We have to set the sizing header and extend
1114*5772Sas200622 		 * the size of the PDU (already done).
1115*5772Sas200622 		 */
1116*5772Sas200622 		rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
1117*5772Sas200622 		if (!rc)
1118*5772Sas200622 			return (0);	/* error already set */
1119*5772Sas200622 		break;
1120*5772Sas200622 
1121*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1122*5772Sas200622 		/*
1123*5772Sas200622 		 * Allocation done during mlndr_conformant_construct().
1124*5772Sas200622 		 * All we are doing here is verifying that the
1125*5772Sas200622 		 * intended size (ref->size_is) matches the sizing header.
1126*5772Sas200622 		 */
1127*5772Sas200622 		if (size_is != outer_ref->size_is) {
1128*5772Sas200622 			NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
1129*5772Sas200622 			return (0);
1130*5772Sas200622 		}
1131*5772Sas200622 		break;
1132*5772Sas200622 
1133*5772Sas200622 	default:
1134*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1135*5772Sas200622 		return (0);
1136*5772Sas200622 	}
1137*5772Sas200622 
1138*5772Sas200622 	outer_ref->inner_flags |= NDR_F_SIZE_IS;
1139*5772Sas200622 	outer_ref->size_is = ref->size_is;
1140*5772Sas200622 	return (1);
1141*5772Sas200622 }
1142*5772Sas200622 
1143*5772Sas200622 int
1144*5772Sas200622 mlndr_outer_string(struct ndr_reference *outer_ref)
1145*5772Sas200622 {
1146*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
1147*5772Sas200622 	struct ndr_typeinfo 	*ti = outer_ref->ti;
1148*5772Sas200622 	struct ndr_reference	myref;
1149*5772Sas200622 	char 		*valp = NULL;
1150*5772Sas200622 	unsigned	is_varlen = ti->pdu_size_variable_part;
1151*5772Sas200622 	int		is_union = NDR_IS_UNION(ti);
1152*5772Sas200622 	int		is_string = NDR_IS_STRING(ti);
1153*5772Sas200622 	int		rc;
1154*5772Sas200622 	unsigned	n_zeroes;
1155*5772Sas200622 	unsigned	ix;
1156*5772Sas200622 	unsigned long	size_is;
1157*5772Sas200622 	unsigned long	first_is;
1158*5772Sas200622 	unsigned long	length_is;
1159*5772Sas200622 	unsigned	n_hdr;
1160*5772Sas200622 	unsigned	n_fixed;
1161*5772Sas200622 	unsigned	n_variable;
1162*5772Sas200622 	unsigned	n_alloc;
1163*5772Sas200622 	unsigned	n_pdu_total;
1164*5772Sas200622 	int		params;
1165*5772Sas200622 
1166*5772Sas200622 	params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1167*5772Sas200622 
1168*5772Sas200622 	assert(is_varlen && is_string && !is_union);
1169*5772Sas200622 	assert(params == NDR_F_NONE);
1170*5772Sas200622 
1171*5772Sas200622 	/* string header for this: size_is first_is length_is */
1172*5772Sas200622 	n_hdr = 12;
1173*5772Sas200622 
1174*5772Sas200622 	/* fixed part -- exactly none of these */
1175*5772Sas200622 	n_fixed = 0;
1176*5772Sas200622 
1177*5772Sas200622 	if (!mlndr_outer_grow(outer_ref, n_hdr))
1178*5772Sas200622 		return (0);		/* error already set */
1179*5772Sas200622 
1180*5772Sas200622 	switch (mlnds->m_op) {
1181*5772Sas200622 	case NDR_M_OP_MARSHALL:
1182*5772Sas200622 		valp = outer_ref->datum;
1183*5772Sas200622 		assert(valp);
1184*5772Sas200622 
1185*5772Sas200622 		if (outer_ref->backptr)
1186*5772Sas200622 			assert(valp == *outer_ref->backptr);
1187*5772Sas200622 
1188*5772Sas200622 		if (ti == &ndt_s_wchar) {
1189*5772Sas200622 			/*
1190*5772Sas200622 			 * size_is is the number of characters in the string,
1191*5772Sas200622 			 * including the null. We assume valp is UTF-8 encoded.
1192*5772Sas200622 			 * We can use mts_wcequiv_strlen for ASCII, extended
1193*5772Sas200622 			 * ASCII or Unicode (UCS-2).
1194*5772Sas200622 			 */
1195*5772Sas200622 			size_is = (mts_wcequiv_strlen(valp) /
1196*5772Sas200622 			    sizeof (mts_wchar_t)) + 1;
1197*5772Sas200622 
1198*5772Sas200622 			if (size_is > NDR_STRING_MAX) {
1199*5772Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1200*5772Sas200622 				return (0);
1201*5772Sas200622 			}
1202*5772Sas200622 		} else {
1203*5772Sas200622 			valp = outer_ref->datum;
1204*5772Sas200622 			n_zeroes = 0;
1205*5772Sas200622 			for (ix = 0; ix < 1024; ix++) {
1206*5772Sas200622 				if (valp[ix] == 0) {
1207*5772Sas200622 					n_zeroes++;
1208*5772Sas200622 					if (n_zeroes >= is_varlen &&
1209*5772Sas200622 					    ix % is_varlen == 0) {
1210*5772Sas200622 						break;
1211*5772Sas200622 					}
1212*5772Sas200622 				} else {
1213*5772Sas200622 					n_zeroes = 0;
1214*5772Sas200622 				}
1215*5772Sas200622 			}
1216*5772Sas200622 			if (ix >= 1024) {
1217*5772Sas200622 				NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1218*5772Sas200622 				return (0);
1219*5772Sas200622 			}
1220*5772Sas200622 			size_is = ix+1;
1221*5772Sas200622 		}
1222*5772Sas200622 
1223*5772Sas200622 		first_is = 0;
1224*5772Sas200622 
1225*5772Sas200622 		if (mlnds->flags & MLNDS_F_NOTERM)
1226*5772Sas200622 			length_is = size_is - 1;
1227*5772Sas200622 		else
1228*5772Sas200622 			length_is = size_is;
1229*5772Sas200622 
1230*5772Sas200622 		if (!mlndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
1231*5772Sas200622 		    !mlndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
1232*5772Sas200622 		    !mlndr_outer_poke_sizing(outer_ref, 8, &length_is))
1233*5772Sas200622 			return (0);		/* error already set */
1234*5772Sas200622 		break;
1235*5772Sas200622 
1236*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1237*5772Sas200622 		if (!mlndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
1238*5772Sas200622 		    !mlndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
1239*5772Sas200622 		    !mlndr_outer_peek_sizing(outer_ref, 8, &length_is))
1240*5772Sas200622 			return (0);		/* error already set */
1241*5772Sas200622 
1242*5772Sas200622 		/*
1243*5772Sas200622 		 * In addition to the first_is check, we used to check that
1244*5772Sas200622 		 * size_is or size_is-1 was equal to length_is but Windows95
1245*5772Sas200622 		 * doesn't conform to this "rule" (see variable part below).
1246*5772Sas200622 		 * The srvmgr tool for Windows95 sent the following values
1247*5772Sas200622 		 * for a path string:
1248*5772Sas200622 		 *
1249*5772Sas200622 		 *	size_is   = 261 (0x105)
1250*5772Sas200622 		 *	first_is  = 0
1251*5772Sas200622 		 *	length_is = 53  (0x35)
1252*5772Sas200622 		 *
1253*5772Sas200622 		 * The length_is was correct (for the given path) but the
1254*5772Sas200622 		 * size_is was the maximum path length rather than being
1255*5772Sas200622 		 * related to length_is.
1256*5772Sas200622 		 */
1257*5772Sas200622 		if (first_is != 0) {
1258*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1259*5772Sas200622 			return (0);
1260*5772Sas200622 		}
1261*5772Sas200622 
1262*5772Sas200622 		if (ti == &ndt_s_wchar) {
1263*5772Sas200622 			/*
1264*5772Sas200622 			 * Decoding Unicode to UTF-8; we need to allow
1265*5772Sas200622 			 * for the maximum possible char size. It would
1266*5772Sas200622 			 * be nice to use mbequiv_strlen but the string
1267*5772Sas200622 			 * may not be null terminated.
1268*5772Sas200622 			 */
1269*5772Sas200622 			n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
1270*5772Sas200622 		} else {
1271*5772Sas200622 			n_alloc = (size_is + 1) * is_varlen;
1272*5772Sas200622 		}
1273*5772Sas200622 
1274*5772Sas200622 		valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref);
1275*5772Sas200622 		if (!valp) {
1276*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1277*5772Sas200622 			return (0);
1278*5772Sas200622 		}
1279*5772Sas200622 
1280*5772Sas200622 		bzero(valp, (size_is+1) * is_varlen);
1281*5772Sas200622 
1282*5772Sas200622 		if (outer_ref->backptr)
1283*5772Sas200622 			*outer_ref->backptr = valp;
1284*5772Sas200622 		outer_ref->datum = valp;
1285*5772Sas200622 		break;
1286*5772Sas200622 
1287*5772Sas200622 	default:
1288*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1289*5772Sas200622 		return (0);
1290*5772Sas200622 	}
1291*5772Sas200622 
1292*5772Sas200622 	/*
1293*5772Sas200622 	 * Variable part - exactly length_is of these.
1294*5772Sas200622 	 *
1295*5772Sas200622 	 * Usually, length_is is same as size_is and includes nul.
1296*5772Sas200622 	 * Some protocols use length_is = size_is-1, and length_is does
1297*5772Sas200622 	 * not include the nul (which is more consistent with DCE spec).
1298*5772Sas200622 	 * If the length_is is 0, there is no data following the
1299*5772Sas200622 	 * sizing header, regardless of size_is.
1300*5772Sas200622 	 */
1301*5772Sas200622 	n_variable = length_is * is_varlen;
1302*5772Sas200622 
1303*5772Sas200622 	/* sum them up to determine the PDU space required */
1304*5772Sas200622 	n_pdu_total = n_hdr + n_fixed + n_variable;
1305*5772Sas200622 
1306*5772Sas200622 	/* similar sum to determine how much local memory is required */
1307*5772Sas200622 	n_alloc = n_fixed + n_variable;
1308*5772Sas200622 
1309*5772Sas200622 	rc = mlndr_outer_grow(outer_ref, n_pdu_total);
1310*5772Sas200622 	if (!rc)
1311*5772Sas200622 		return (rc);		/* error already set */
1312*5772Sas200622 
1313*5772Sas200622 	if (length_is > 0) {
1314*5772Sas200622 		bzero(&myref, sizeof (myref));
1315*5772Sas200622 		myref.stream = mlnds;
1316*5772Sas200622 		myref.enclosing = outer_ref;
1317*5772Sas200622 		myref.ti = outer_ref->ti;
1318*5772Sas200622 		myref.datum = outer_ref->datum;
1319*5772Sas200622 		myref.name = "OUTER-STRING";
1320*5772Sas200622 		myref.outer_flags = NDR_F_IS_STRING;
1321*5772Sas200622 		myref.inner_flags = NDR_F_NONE;
1322*5772Sas200622 
1323*5772Sas200622 		/*
1324*5772Sas200622 		 * Set up size_is and strlen_is for mlndr_s_wchar.
1325*5772Sas200622 		 */
1326*5772Sas200622 		myref.size_is = size_is;
1327*5772Sas200622 		myref.strlen_is = length_is;
1328*5772Sas200622 	}
1329*5772Sas200622 
1330*5772Sas200622 	myref.pdu_offset = outer_ref->pdu_offset + 12;
1331*5772Sas200622 
1332*5772Sas200622 	/*
1333*5772Sas200622 	 * Don't try to decode empty strings.
1334*5772Sas200622 	 */
1335*5772Sas200622 	if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
1336*5772Sas200622 		mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
1337*5772Sas200622 		return (1);
1338*5772Sas200622 	}
1339*5772Sas200622 
1340*5772Sas200622 	if ((size_is != 0) && (length_is != 0)) {
1341*5772Sas200622 		rc = mlndr_inner(&myref);
1342*5772Sas200622 		if (!rc)
1343*5772Sas200622 			return (rc);		/* error already set */
1344*5772Sas200622 	}
1345*5772Sas200622 
1346*5772Sas200622 	mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
1347*5772Sas200622 	return (1);
1348*5772Sas200622 }
1349*5772Sas200622 
1350*5772Sas200622 int
1351*5772Sas200622 mlndr_outer_peek_sizing(struct ndr_reference *outer_ref, unsigned offset,
1352*5772Sas200622     unsigned long *sizing_p)
1353*5772Sas200622 {
1354*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
1355*5772Sas200622 	unsigned long		pdu_offset;
1356*5772Sas200622 	int			rc;
1357*5772Sas200622 
1358*5772Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
1359*5772Sas200622 
1360*5772Sas200622 	if (pdu_offset < mlnds->outer_current->pdu_offset ||
1361*5772Sas200622 	    pdu_offset > mlnds->outer_current->pdu_end_offset ||
1362*5772Sas200622 	    pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
1363*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1364*5772Sas200622 		return (0);
1365*5772Sas200622 	}
1366*5772Sas200622 
1367*5772Sas200622 	switch (mlnds->m_op) {
1368*5772Sas200622 	case NDR_M_OP_MARSHALL:
1369*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1370*5772Sas200622 		return (0);
1371*5772Sas200622 
1372*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1373*5772Sas200622 		rc = MLNDS_GET_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
1374*5772Sas200622 		    mlnds->swap, outer_ref);
1375*5772Sas200622 		break;
1376*5772Sas200622 
1377*5772Sas200622 	default:
1378*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1379*5772Sas200622 		return (0);
1380*5772Sas200622 	}
1381*5772Sas200622 
1382*5772Sas200622 	return (rc);
1383*5772Sas200622 }
1384*5772Sas200622 
1385*5772Sas200622 int
1386*5772Sas200622 mlndr_outer_poke_sizing(struct ndr_reference *outer_ref, unsigned offset,
1387*5772Sas200622     unsigned long *sizing_p)
1388*5772Sas200622 {
1389*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
1390*5772Sas200622 	unsigned long		pdu_offset;
1391*5772Sas200622 	int			rc;
1392*5772Sas200622 
1393*5772Sas200622 	pdu_offset = outer_ref->pdu_offset + offset;
1394*5772Sas200622 
1395*5772Sas200622 	if (pdu_offset < mlnds->outer_current->pdu_offset ||
1396*5772Sas200622 	    pdu_offset > mlnds->outer_current->pdu_end_offset ||
1397*5772Sas200622 	    pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
1398*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1399*5772Sas200622 		return (0);
1400*5772Sas200622 	}
1401*5772Sas200622 
1402*5772Sas200622 	switch (mlnds->m_op) {
1403*5772Sas200622 	case NDR_M_OP_MARSHALL:
1404*5772Sas200622 		rc = MLNDS_PUT_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
1405*5772Sas200622 		    mlnds->swap, outer_ref);
1406*5772Sas200622 		break;
1407*5772Sas200622 
1408*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1409*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1410*5772Sas200622 		return (0);
1411*5772Sas200622 
1412*5772Sas200622 	default:
1413*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1414*5772Sas200622 		return (0);
1415*5772Sas200622 	}
1416*5772Sas200622 
1417*5772Sas200622 	return (rc);
1418*5772Sas200622 }
1419*5772Sas200622 
1420*5772Sas200622 /*
1421*5772Sas200622  * All OUTER constructs begin on a mod4 (dword) boundary - except
1422*5772Sas200622  * for the ones that don't: some MSRPC calls appear to use word or
1423*5772Sas200622  * packed alignment.  Strings appear to be dword aligned.
1424*5772Sas200622  */
1425*5772Sas200622 int
1426*5772Sas200622 mlndr_outer_align(struct ndr_reference *outer_ref)
1427*5772Sas200622 {
1428*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
1429*5772Sas200622 	int			rc;
1430*5772Sas200622 	unsigned		n_pad;
1431*5772Sas200622 	unsigned		align;
1432*5772Sas200622 
1433*5772Sas200622 	if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1434*5772Sas200622 		align = outer_ref->ti->alignment;
1435*5772Sas200622 		n_pad = ((align + 1) - mlnds->pdu_scan_offset) & align;
1436*5772Sas200622 	} else {
1437*5772Sas200622 		n_pad = (4 - mlnds->pdu_scan_offset) & 3;
1438*5772Sas200622 	}
1439*5772Sas200622 
1440*5772Sas200622 	if (n_pad == 0)
1441*5772Sas200622 		return (1);	/* already aligned, often the case */
1442*5772Sas200622 
1443*5772Sas200622 	if (!mlndr_outer_grow(outer_ref, n_pad))
1444*5772Sas200622 		return (0);	/* error already set */
1445*5772Sas200622 
1446*5772Sas200622 	switch (mlnds->m_op) {
1447*5772Sas200622 	case NDR_M_OP_MARSHALL:
1448*5772Sas200622 		rc = MLNDS_PAD_PDU(mlnds,
1449*5772Sas200622 		    mlnds->pdu_scan_offset, n_pad, outer_ref);
1450*5772Sas200622 		if (!rc) {
1451*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1452*5772Sas200622 			return (0);
1453*5772Sas200622 		}
1454*5772Sas200622 		break;
1455*5772Sas200622 
1456*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1457*5772Sas200622 		break;
1458*5772Sas200622 
1459*5772Sas200622 	default:
1460*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1461*5772Sas200622 		return (0);
1462*5772Sas200622 	}
1463*5772Sas200622 
1464*5772Sas200622 	mlnds->pdu_scan_offset += n_pad;
1465*5772Sas200622 	return (1);
1466*5772Sas200622 }
1467*5772Sas200622 
1468*5772Sas200622 int
1469*5772Sas200622 mlndr_outer_grow(struct ndr_reference *outer_ref, unsigned n_total)
1470*5772Sas200622 {
1471*5772Sas200622 	struct mlndr_stream 	*mlnds = outer_ref->stream;
1472*5772Sas200622 	unsigned long		pdu_want_size;
1473*5772Sas200622 	int			rc, is_ok = 0;
1474*5772Sas200622 
1475*5772Sas200622 	pdu_want_size = mlnds->pdu_scan_offset + n_total;
1476*5772Sas200622 
1477*5772Sas200622 	if (pdu_want_size <= mlnds->pdu_max_size) {
1478*5772Sas200622 		is_ok = 1;
1479*5772Sas200622 	}
1480*5772Sas200622 
1481*5772Sas200622 	switch (mlnds->m_op) {
1482*5772Sas200622 	case NDR_M_OP_MARSHALL:
1483*5772Sas200622 		if (is_ok)
1484*5772Sas200622 			break;
1485*5772Sas200622 		rc = MLNDS_GROW_PDU(mlnds, pdu_want_size, outer_ref);
1486*5772Sas200622 		if (!rc) {
1487*5772Sas200622 			NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1488*5772Sas200622 			return (0);
1489*5772Sas200622 		}
1490*5772Sas200622 		break;
1491*5772Sas200622 
1492*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1493*5772Sas200622 		if (is_ok)
1494*5772Sas200622 			break;
1495*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1496*5772Sas200622 		return (0);
1497*5772Sas200622 
1498*5772Sas200622 	default:
1499*5772Sas200622 		NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1500*5772Sas200622 		return (0);
1501*5772Sas200622 	}
1502*5772Sas200622 
1503*5772Sas200622 	if (mlnds->pdu_size < pdu_want_size)
1504*5772Sas200622 		mlnds->pdu_size = pdu_want_size;
1505*5772Sas200622 
1506*5772Sas200622 	outer_ref->pdu_end_offset = pdu_want_size;
1507*5772Sas200622 	return (1);
1508*5772Sas200622 }
1509*5772Sas200622 
1510*5772Sas200622 /*
1511*5772Sas200622  * INNER ELEMENTS
1512*5772Sas200622  *
1513*5772Sas200622  * The local datum (arg_ref->datum) already exists, there is no need to
1514*5772Sas200622  * malloc() it.  The datum should point at a member of a structure.
1515*5772Sas200622  *
1516*5772Sas200622  * For the most part, mlndr_inner() and its helpers are just a sanity
1517*5772Sas200622  * check.  The underlying ti->ndr_func() could be called immediately
1518*5772Sas200622  * for non-pointer elements.  For the sake of robustness, we detect
1519*5772Sas200622  * run-time errors here.  Most of the situations this protects against
1520*5772Sas200622  * have already been checked by the IDL compiler.  This is also a
1521*5772Sas200622  * common point for processing of all data, and so is a convenient
1522*5772Sas200622  * place to work from for debugging.
1523*5772Sas200622  */
1524*5772Sas200622 int
1525*5772Sas200622 mlndr_inner(struct ndr_reference *arg_ref)
1526*5772Sas200622 {
1527*5772Sas200622 	struct ndr_typeinfo 	*ti = arg_ref->ti;
1528*5772Sas200622 	int	is_varlen = ti->pdu_size_variable_part;
1529*5772Sas200622 	int	is_union = NDR_IS_UNION(ti);
1530*5772Sas200622 	int	error = NDR_ERR_INNER_PARAMS_BAD;
1531*5772Sas200622 	int	params;
1532*5772Sas200622 
1533*5772Sas200622 	params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1534*5772Sas200622 
1535*5772Sas200622 	switch (params) {
1536*5772Sas200622 	case NDR_F_NONE:
1537*5772Sas200622 		if (is_union) {
1538*5772Sas200622 			error = NDR_ERR_SWITCH_VALUE_MISSING;
1539*5772Sas200622 			break;
1540*5772Sas200622 		}
1541*5772Sas200622 		return (*ti->ndr_func)(arg_ref);
1542*5772Sas200622 		break;
1543*5772Sas200622 
1544*5772Sas200622 	case NDR_F_SIZE_IS:
1545*5772Sas200622 	case NDR_F_DIMENSION_IS:
1546*5772Sas200622 	case NDR_F_IS_POINTER+NDR_F_SIZE_IS:   /* pointer to something */
1547*5772Sas200622 	case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1548*5772Sas200622 		if (is_varlen) {
1549*5772Sas200622 			error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1550*5772Sas200622 			break;
1551*5772Sas200622 		}
1552*5772Sas200622 		if (is_union) {
1553*5772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1554*5772Sas200622 			break;
1555*5772Sas200622 		}
1556*5772Sas200622 		if (params & NDR_F_IS_POINTER)
1557*5772Sas200622 			return (mlndr_inner_pointer(arg_ref));
1558*5772Sas200622 		else if (params & NDR_F_IS_REFERENCE)
1559*5772Sas200622 			return (mlndr_inner_reference(arg_ref));
1560*5772Sas200622 		else
1561*5772Sas200622 			return (mlndr_inner_array(arg_ref));
1562*5772Sas200622 		break;
1563*5772Sas200622 
1564*5772Sas200622 	case NDR_F_IS_POINTER:	/* type is pointer to one something */
1565*5772Sas200622 		if (is_union) {
1566*5772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1567*5772Sas200622 			break;
1568*5772Sas200622 		}
1569*5772Sas200622 		return (mlndr_inner_pointer(arg_ref));
1570*5772Sas200622 		break;
1571*5772Sas200622 
1572*5772Sas200622 	case NDR_F_IS_REFERENCE:	/* type is pointer to one something */
1573*5772Sas200622 		if (is_union) {
1574*5772Sas200622 			error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1575*5772Sas200622 			break;
1576*5772Sas200622 		}
1577*5772Sas200622 		return (mlndr_inner_reference(arg_ref));
1578*5772Sas200622 		break;
1579*5772Sas200622 
1580*5772Sas200622 	case NDR_F_SWITCH_IS:
1581*5772Sas200622 		if (!is_union) {
1582*5772Sas200622 			error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1583*5772Sas200622 			break;
1584*5772Sas200622 		}
1585*5772Sas200622 		return (*ti->ndr_func)(arg_ref);
1586*5772Sas200622 		break;
1587*5772Sas200622 
1588*5772Sas200622 	default:
1589*5772Sas200622 		error = NDR_ERR_INNER_PARAMS_BAD;
1590*5772Sas200622 		break;
1591*5772Sas200622 	}
1592*5772Sas200622 
1593*5772Sas200622 	/*
1594*5772Sas200622 	 * If we get here, something is wrong. Most likely,
1595*5772Sas200622 	 * the params flags do not match
1596*5772Sas200622 	 */
1597*5772Sas200622 	NDR_SET_ERROR(arg_ref, error);
1598*5772Sas200622 	return (0);
1599*5772Sas200622 }
1600*5772Sas200622 
1601*5772Sas200622 int
1602*5772Sas200622 mlndr_inner_pointer(struct ndr_reference *arg_ref)
1603*5772Sas200622 {
1604*5772Sas200622 	struct mlndr_stream 	*mlnds = arg_ref->stream;
1605*5772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1606*5772Sas200622 	char 			**valpp = (char **)arg_ref->datum;
1607*5772Sas200622 	struct ndr_reference 	*outer_ref;
1608*5772Sas200622 
1609*5772Sas200622 	if (!mlndr__ulong(arg_ref))
1610*5772Sas200622 		return (0);	/* error */
1611*5772Sas200622 	if (!*valpp)
1612*5772Sas200622 		return (1);	/* NULL pointer */
1613*5772Sas200622 
1614*5772Sas200622 	outer_ref = mlndr_enter_outer_queue(arg_ref);
1615*5772Sas200622 	if (!outer_ref)
1616*5772Sas200622 		return (0);	/* error already set */
1617*5772Sas200622 
1618*5772Sas200622 	/* move advice in inner_flags to outer_flags sans pointer */
1619*5772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1620*5772Sas200622 	outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1621*5772Sas200622 #ifdef NDR_INNER_NOT_YET
1622*5772Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1623*5772Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1624*5772Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1625*5772Sas200622 	}
1626*5772Sas200622 #endif /* NDR_INNER_NOT_YET */
1627*5772Sas200622 
1628*5772Sas200622 	outer_ref->backptr = valpp;
1629*5772Sas200622 
1630*5772Sas200622 	switch (mlnds->m_op) {
1631*5772Sas200622 	case NDR_M_OP_MARSHALL:
1632*5772Sas200622 		outer_ref->datum = *valpp;
1633*5772Sas200622 		break;
1634*5772Sas200622 
1635*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1636*5772Sas200622 		/*
1637*5772Sas200622 		 * This is probably wrong if the application allocated
1638*5772Sas200622 		 * memory in advance.  Indicate no value for now.
1639*5772Sas200622 		 * ONC RPC handles this case.
1640*5772Sas200622 		 */
1641*5772Sas200622 		*valpp = 0;
1642*5772Sas200622 		outer_ref->datum = 0;
1643*5772Sas200622 		break;
1644*5772Sas200622 	}
1645*5772Sas200622 
1646*5772Sas200622 	return (1);		/* pointer dereference scheduled */
1647*5772Sas200622 }
1648*5772Sas200622 
1649*5772Sas200622 int
1650*5772Sas200622 mlndr_inner_reference(struct ndr_reference *arg_ref)
1651*5772Sas200622 {
1652*5772Sas200622 	struct mlndr_stream	*mlnds = arg_ref->stream;
1653*5772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1654*5772Sas200622 	char			**valpp = (char **)arg_ref->datum;
1655*5772Sas200622 	struct ndr_reference	*outer_ref;
1656*5772Sas200622 
1657*5772Sas200622 	outer_ref = mlndr_enter_outer_queue(arg_ref);
1658*5772Sas200622 	if (!outer_ref)
1659*5772Sas200622 		return (0);	/* error already set */
1660*5772Sas200622 
1661*5772Sas200622 	/* move advice in inner_flags to outer_flags sans pointer */
1662*5772Sas200622 	outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1663*5772Sas200622 	outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1664*5772Sas200622 #ifdef NDR_INNER_REF_NOT_YET
1665*5772Sas200622 	outer_ref->outer_flags |= NDR_F_BACKPTR;
1666*5772Sas200622 	if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1667*5772Sas200622 		outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1668*5772Sas200622 	}
1669*5772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */
1670*5772Sas200622 
1671*5772Sas200622 	outer_ref->backptr = valpp;
1672*5772Sas200622 
1673*5772Sas200622 	switch (mlnds->m_op) {
1674*5772Sas200622 	case NDR_M_OP_MARSHALL:
1675*5772Sas200622 		outer_ref->datum = *valpp;
1676*5772Sas200622 		break;
1677*5772Sas200622 
1678*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1679*5772Sas200622 		/*
1680*5772Sas200622 		 * This is probably wrong if the application allocated
1681*5772Sas200622 		 * memory in advance.  Indicate no value for now.
1682*5772Sas200622 		 * ONC RPC handles this case.
1683*5772Sas200622 		 */
1684*5772Sas200622 		*valpp = 0;
1685*5772Sas200622 		outer_ref->datum = 0;
1686*5772Sas200622 		break;
1687*5772Sas200622 	}
1688*5772Sas200622 
1689*5772Sas200622 	return (1);		/* pointer dereference scheduled */
1690*5772Sas200622 }
1691*5772Sas200622 
1692*5772Sas200622 int
1693*5772Sas200622 mlndr_inner_array(struct ndr_reference *encl_ref)
1694*5772Sas200622 {
1695*5772Sas200622 	struct ndr_typeinfo	*ti = encl_ref->ti;
1696*5772Sas200622 	struct ndr_reference	myref;
1697*5772Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1698*5772Sas200622 	unsigned long		n_elem;
1699*5772Sas200622 	unsigned long		i;
1700*5772Sas200622 	char			name[30];
1701*5772Sas200622 
1702*5772Sas200622 	if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1703*5772Sas200622 		/* now is the time to check/set size */
1704*5772Sas200622 		if (!mlndr_size_is(encl_ref))
1705*5772Sas200622 			return (0);	/* error already set */
1706*5772Sas200622 		n_elem = encl_ref->size_is;
1707*5772Sas200622 	} else {
1708*5772Sas200622 		assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1709*5772Sas200622 		n_elem = encl_ref->dimension_is;
1710*5772Sas200622 	}
1711*5772Sas200622 
1712*5772Sas200622 	bzero(&myref, sizeof (myref));
1713*5772Sas200622 	myref.enclosing = encl_ref;
1714*5772Sas200622 	myref.stream = encl_ref->stream;
1715*5772Sas200622 	myref.packed_alignment = 0;
1716*5772Sas200622 	myref.ti = ti;
1717*5772Sas200622 	myref.inner_flags = NDR_F_NONE;
1718*5772Sas200622 
1719*5772Sas200622 	for (i = 0; i < n_elem; i++) {
1720*5772Sas200622 		(void) sprintf(name, "[%lu]", i);
1721*5772Sas200622 		myref.name = name;
1722*5772Sas200622 		myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1723*5772Sas200622 		myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1724*5772Sas200622 
1725*5772Sas200622 		if (!mlndr_inner(&myref))
1726*5772Sas200622 			return (0);
1727*5772Sas200622 	}
1728*5772Sas200622 
1729*5772Sas200622 	return (1);
1730*5772Sas200622 }
1731*5772Sas200622 
1732*5772Sas200622 
1733*5772Sas200622 /*
1734*5772Sas200622  * BASIC TYPES
1735*5772Sas200622  */
1736*5772Sas200622 #define	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1737*5772Sas200622     extern int mlndr_##TYPE(struct ndr_reference *encl_ref); \
1738*5772Sas200622     struct ndr_typeinfo ndt_##TYPE = { \
1739*5772Sas200622 	1,		/* NDR version */ \
1740*5772Sas200622 	(SIZE)-1,	/* alignment */ \
1741*5772Sas200622 	NDR_F_NONE,	/* flags */ \
1742*5772Sas200622 	mlndr_##TYPE,	/* ndr_func */ \
1743*5772Sas200622 	SIZE,		/* pdu_size_fixed_part */ \
1744*5772Sas200622 	0,		/* pdu_size_variable_part */ \
1745*5772Sas200622 	SIZE,		/* c_size_fixed_part */ \
1746*5772Sas200622 	0,		/* c_size_variable_part */ \
1747*5772Sas200622 	}; \
1748*5772Sas200622     int mlndr_##TYPE(struct ndr_reference *ref) { \
1749*5772Sas200622 	return (mlndr_basic_integer(ref, SIZE)); \
1750*5772Sas200622 }
1751*5772Sas200622 
1752*5772Sas200622 #define	MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
1753*5772Sas200622     extern int mlndr_s##TYPE(struct ndr_reference *encl_ref); \
1754*5772Sas200622     struct ndr_typeinfo ndt_s##TYPE = { \
1755*5772Sas200622 	1,		/* NDR version */ \
1756*5772Sas200622 	(SIZE)-1,	/* alignment */ \
1757*5772Sas200622 	NDR_F_STRING,	/* flags */ \
1758*5772Sas200622 	mlndr_s##TYPE,	/* ndr_func */ \
1759*5772Sas200622 	0,		/* pdu_size_fixed_part */ \
1760*5772Sas200622 	SIZE,		/* pdu_size_variable_part */ \
1761*5772Sas200622 	0,		/* c_size_fixed_part */ \
1762*5772Sas200622 	SIZE,		/* c_size_variable_part */ \
1763*5772Sas200622 	}; \
1764*5772Sas200622     int mlndr_s##TYPE(struct ndr_reference *ref) { \
1765*5772Sas200622 	return (mlndr_string_basic_integer(ref, &ndt_##TYPE)); \
1766*5772Sas200622 }
1767*5772Sas200622 
1768*5772Sas200622 #define	MAKE_BASIC_TYPE(TYPE, SIZE) \
1769*5772Sas200622 	MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1770*5772Sas200622 	MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1771*5772Sas200622 
1772*5772Sas200622 extern int
1773*5772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size);
1774*5772Sas200622 
1775*5772Sas200622 extern int
1776*5772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref,
1777*5772Sas200622     struct ndr_typeinfo *type_under);
1778*5772Sas200622 
1779*5772Sas200622 
1780*5772Sas200622 MAKE_BASIC_TYPE(_char, 1)
1781*5772Sas200622 MAKE_BASIC_TYPE(_uchar, 1)
1782*5772Sas200622 MAKE_BASIC_TYPE(_short, 2)
1783*5772Sas200622 MAKE_BASIC_TYPE(_ushort, 2)
1784*5772Sas200622 MAKE_BASIC_TYPE(_long, 4)
1785*5772Sas200622 MAKE_BASIC_TYPE(_ulong, 4)
1786*5772Sas200622 
1787*5772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2)
1788*5772Sas200622 
1789*5772Sas200622 int
1790*5772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size)
1791*5772Sas200622 {
1792*5772Sas200622 	struct mlndr_stream 	*mlnds = ref->stream;
1793*5772Sas200622 	char 			*valp = (char *)ref->datum;
1794*5772Sas200622 	int			rc;
1795*5772Sas200622 
1796*5772Sas200622 	switch (mlnds->m_op) {
1797*5772Sas200622 	case NDR_M_OP_MARSHALL:
1798*5772Sas200622 		rc = MLNDS_PUT_PDU(mlnds, ref->pdu_offset, size,
1799*5772Sas200622 		    valp, mlnds->swap, ref);
1800*5772Sas200622 		break;
1801*5772Sas200622 
1802*5772Sas200622 	case NDR_M_OP_UNMARSHALL:
1803*5772Sas200622 		rc = MLNDS_GET_PDU(mlnds, ref->pdu_offset, size,
1804*5772Sas200622 		    valp, mlnds->swap, ref);
1805*5772Sas200622 		break;
1806*5772Sas200622 
1807*5772Sas200622 	default:
1808*5772Sas200622 		NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1809*5772Sas200622 		return (0);
1810*5772Sas200622 	}
1811*5772Sas200622 
1812*5772Sas200622 	return (rc);
1813*5772Sas200622 }
1814*5772Sas200622 
1815*5772Sas200622 int
1816*5772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref,
1817*5772Sas200622     struct ndr_typeinfo *type_under)
1818*5772Sas200622 {
1819*5772Sas200622 	unsigned long		pdu_offset = encl_ref->pdu_offset;
1820*5772Sas200622 	unsigned		size = type_under->pdu_size_fixed_part;
1821*5772Sas200622 	char			*valp;
1822*5772Sas200622 	struct ndr_reference	myref;
1823*5772Sas200622 	unsigned long		i;
1824*5772Sas200622 	long			sense = 0;
1825*5772Sas200622 	char			name[30];
1826*5772Sas200622 
1827*5772Sas200622 	assert(size != 0);
1828*5772Sas200622 
1829*5772Sas200622 	bzero(&myref, sizeof (myref));
1830*5772Sas200622 	myref.enclosing = encl_ref;
1831*5772Sas200622 	myref.stream = encl_ref->stream;
1832*5772Sas200622 	myref.packed_alignment = 0;
1833*5772Sas200622 	myref.ti = type_under;
1834*5772Sas200622 	myref.inner_flags = NDR_F_NONE;
1835*5772Sas200622 	myref.name = name;
1836*5772Sas200622 
1837*5772Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
1838*5772Sas200622 		(void) sprintf(name, "[%lu]", i);
1839*5772Sas200622 		myref.pdu_offset = pdu_offset + i * size;
1840*5772Sas200622 		valp = encl_ref->datum + i * size;
1841*5772Sas200622 		myref.datum = valp;
1842*5772Sas200622 
1843*5772Sas200622 		if (!mlndr_inner(&myref))
1844*5772Sas200622 			return (0);
1845*5772Sas200622 
1846*5772Sas200622 		switch (size) {
1847*5772Sas200622 		case 1:		sense = *valp; break;
1848*5772Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1849*5772Sas200622 		case 2:		sense = *(short *)valp; break;
1850*5772Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1851*5772Sas200622 		case 4:		sense = *(long *)valp; break;
1852*5772Sas200622 		}
1853*5772Sas200622 
1854*5772Sas200622 		if (!sense)
1855*5772Sas200622 			break;
1856*5772Sas200622 	}
1857*5772Sas200622 
1858*5772Sas200622 	return (1);
1859*5772Sas200622 }
1860*5772Sas200622 
1861*5772Sas200622 
1862*5772Sas200622 extern int mlndr_s_wchar(struct ndr_reference *encl_ref);
1863*5772Sas200622 struct ndr_typeinfo ndt_s_wchar = {
1864*5772Sas200622 	1,		/* NDR version */
1865*5772Sas200622 	2-1,		/* alignment */
1866*5772Sas200622 	NDR_F_STRING,	/* flags */
1867*5772Sas200622 	mlndr_s_wchar,	/* ndr_func */
1868*5772Sas200622 	0,		/* pdu_size_fixed_part */
1869*5772Sas200622 	2,		/* pdu_size_variable_part */
1870*5772Sas200622 	0,		/* c_size_fixed_part */
1871*5772Sas200622 	1,		/* c_size_variable_part */
1872*5772Sas200622 };
1873*5772Sas200622 
1874*5772Sas200622 
1875*5772Sas200622 /*
1876*5772Sas200622  * Hand coded wchar function because all strings are transported
1877*5772Sas200622  * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1878*5772Sas200622  * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1879*5772Sas200622  * convert from wide characters to multi-byte.
1880*5772Sas200622  *
1881*5772Sas200622  * It appeared that NT would sometimes leave a spurious character
1882*5772Sas200622  * in the data stream before the null wide_char, which would get
1883*5772Sas200622  * included in the string decode because we processed until the
1884*5772Sas200622  * null character. It now looks like NT does not always terminate
1885*5772Sas200622  * RPC Unicode strings and the terminating null is a side effect
1886*5772Sas200622  * of field alignment. So now we rely on the strlen_is (set up in
1887*5772Sas200622  * mlndr_outer_string) of the enclosing reference. This may or may
1888*5772Sas200622  * not include the null but it doesn't matter, the algorithm will
1889*5772Sas200622  * get it right.
1890*5772Sas200622  */
1891*5772Sas200622 int
1892*5772Sas200622 mlndr_s_wchar(struct ndr_reference *encl_ref)
1893*5772Sas200622 {
1894*5772Sas200622 	struct mlndr_stream 	*mlnds = encl_ref->stream;
1895*5772Sas200622 	unsigned short		wide_char;
1896*5772Sas200622 	char 			*valp;
1897*5772Sas200622 	struct ndr_reference	myref;
1898*5772Sas200622 	unsigned long		i;
1899*5772Sas200622 	char			name[30];
1900*5772Sas200622 	int			count;
1901*5772Sas200622 	int			char_count = 0;
1902*5772Sas200622 
1903*5772Sas200622 	if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
1904*5772Sas200622 		/*
1905*5772Sas200622 		 * To avoid problems with zero length strings
1906*5772Sas200622 		 * we can just null terminate here and be done.
1907*5772Sas200622 		 */
1908*5772Sas200622 		if (encl_ref->strlen_is == 0) {
1909*5772Sas200622 			encl_ref->datum[0] = '\0';
1910*5772Sas200622 			return (1);
1911*5772Sas200622 		}
1912*5772Sas200622 	}
1913*5772Sas200622 
1914*5772Sas200622 	bzero(&myref, sizeof (myref));
1915*5772Sas200622 	myref.enclosing = encl_ref;
1916*5772Sas200622 	myref.stream = encl_ref->stream;
1917*5772Sas200622 	myref.packed_alignment = 0;
1918*5772Sas200622 	myref.ti = &ndt__wchar;
1919*5772Sas200622 	myref.inner_flags = NDR_F_NONE;
1920*5772Sas200622 	myref.datum = (char *)&wide_char;
1921*5772Sas200622 	myref.name = name;
1922*5772Sas200622 	myref.pdu_offset = encl_ref->pdu_offset;
1923*5772Sas200622 
1924*5772Sas200622 	valp = encl_ref->datum;
1925*5772Sas200622 	count = 0;
1926*5772Sas200622 
1927*5772Sas200622 	for (i = 0; i < NDR_STRING_MAX; i++) {
1928*5772Sas200622 		(void) sprintf(name, "[%lu]", i);
1929*5772Sas200622 
1930*5772Sas200622 		if (mlnds->m_op == NDR_M_OP_MARSHALL) {
1931*5772Sas200622 			count = mts_mbtowc((mts_wchar_t *)&wide_char, valp,
1932*5772Sas200622 			    MTS_MB_CHAR_MAX);
1933*5772Sas200622 			if (count < 0) {
1934*5772Sas200622 				return (0);
1935*5772Sas200622 			} else if (count == 0) {
1936*5772Sas200622 				if (encl_ref->strlen_is != encl_ref->size_is)
1937*5772Sas200622 					break;
1938*5772Sas200622 
1939*5772Sas200622 				/*
1940*5772Sas200622 				 * If the input char is 0, mbtowc
1941*5772Sas200622 				 * returns 0 without setting wide_char.
1942*5772Sas200622 				 * Set wide_char to 0 and a count of 1.
1943*5772Sas200622 				 */
1944*5772Sas200622 				wide_char = *valp;
1945*5772Sas200622 				count = 1;
1946*5772Sas200622 			}
1947*5772Sas200622 		}
1948*5772Sas200622 
1949*5772Sas200622 		if (!mlndr_inner(&myref))
1950*5772Sas200622 			return (0);
1951*5772Sas200622 
1952*5772Sas200622 		if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
1953*5772Sas200622 			count = mts_wctomb(valp, wide_char);
1954*5772Sas200622 
1955*5772Sas200622 			if ((++char_count) == encl_ref->strlen_is) {
1956*5772Sas200622 				valp += count;
1957*5772Sas200622 				*valp = '\0';
1958*5772Sas200622 				break;
1959*5772Sas200622 			}
1960*5772Sas200622 		}
1961*5772Sas200622 
1962*5772Sas200622 		if (!wide_char)
1963*5772Sas200622 			break;
1964*5772Sas200622 
1965*5772Sas200622 		myref.pdu_offset += sizeof (wide_char);
1966*5772Sas200622 		valp += count;
1967*5772Sas200622 	}
1968*5772Sas200622 
1969*5772Sas200622 	return (1);
1970*5772Sas200622 }
1971*5772Sas200622 
1972*5772Sas200622 /*
1973*5772Sas200622  * Converts a multibyte character string to a little-endian, wide-char
1974*5772Sas200622  * string.  No more than nwchars wide characters are stored.
1975*5772Sas200622  * A terminating null wide character is appended if there is room.
1976*5772Sas200622  *
1977*5772Sas200622  * Returns the number of wide characters converted, not counting
1978*5772Sas200622  * any terminating null wide character.  Returns -1 if an invalid
1979*5772Sas200622  * multibyte character is encountered.
1980*5772Sas200622  */
1981*5772Sas200622 size_t
1982*5772Sas200622 ndr_mbstowcs(struct mlndr_stream *mlnds, mts_wchar_t *wcs, const char *mbs,
1983*5772Sas200622     size_t nwchars)
1984*5772Sas200622 {
1985*5772Sas200622 	mts_wchar_t *start = wcs;
1986*5772Sas200622 	int nbytes;
1987*5772Sas200622 
1988*5772Sas200622 	while (nwchars--) {
1989*5772Sas200622 		nbytes = ndr_mbtowc(mlnds, wcs, mbs, MTS_MB_CHAR_MAX);
1990*5772Sas200622 		if (nbytes < 0) {
1991*5772Sas200622 			*wcs = 0;
1992*5772Sas200622 			return ((size_t)-1);
1993*5772Sas200622 		}
1994*5772Sas200622 
1995*5772Sas200622 		if (*mbs == 0)
1996*5772Sas200622 			break;
1997*5772Sas200622 
1998*5772Sas200622 		++wcs;
1999*5772Sas200622 		mbs += nbytes;
2000*5772Sas200622 	}
2001*5772Sas200622 
2002*5772Sas200622 	return (wcs - start);
2003*5772Sas200622 }
2004*5772Sas200622 
2005*5772Sas200622 /*
2006*5772Sas200622  * Converts a multibyte character to a little-endian, wide-char, which
2007*5772Sas200622  * is stored in wcharp.  Up to nbytes bytes are examined.
2008*5772Sas200622  *
2009*5772Sas200622  * If mbchar is valid, returns the number of bytes processed in mbchar.
2010*5772Sas200622  * If mbchar is invalid, returns -1.  See also mts_mbtowc().
2011*5772Sas200622  */
2012*5772Sas200622 /*ARGSUSED*/
2013*5772Sas200622 int
2014*5772Sas200622 ndr_mbtowc(struct mlndr_stream *mlnds, mts_wchar_t *wcharp,
2015*5772Sas200622     const char *mbchar, size_t nbytes)
2016*5772Sas200622 {
2017*5772Sas200622 	int rc;
2018*5772Sas200622 
2019*5772Sas200622 	if ((rc = mts_mbtowc(wcharp, mbchar, nbytes)) < 0)
2020*5772Sas200622 		return (rc);
2021*5772Sas200622 
2022*5772Sas200622 #ifdef _BIG_ENDIAN
2023*5772Sas200622 	if (mlnds == NULL || NDR_MODE_MATCH(mlnds, NDR_MODE_RETURN_SEND))
2024*5772Sas200622 		*wcharp = BSWAP_16(*wcharp);
2025*5772Sas200622 #endif
2026*5772Sas200622 
2027*5772Sas200622 	return (rc);
2028*5772Sas200622 }
2029