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