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