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