15772Sas200622 /*
25772Sas200622 * CDDL HEADER START
35772Sas200622 *
45772Sas200622 * The contents of this file are subject to the terms of the
55772Sas200622 * Common Development and Distribution License (the "License").
65772Sas200622 * You may not use this file except in compliance with the License.
75772Sas200622 *
85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622 * or http://www.opensolaris.org/os/licensing.
105772Sas200622 * See the License for the specific language governing permissions
115772Sas200622 * and limitations under the License.
125772Sas200622 *
135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622 *
195772Sas200622 * CDDL HEADER END
205772Sas200622 */
215772Sas200622 /*
2211447Samw@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
235772Sas200622 * Use is subject to license terms.
245772Sas200622 */
255772Sas200622
265772Sas200622 /*
275772Sas200622 * Network Data Representation (NDR) is a compatible subset of the DCE RPC
285772Sas200622 * and MSRPC NDR. NDR is used to move parameters consisting of
295772Sas200622 * complicated trees of data constructs between an RPC client and server.
305772Sas200622 */
315772Sas200622
325772Sas200622 #include <sys/byteorder.h>
335772Sas200622 #include <strings.h>
345772Sas200622 #include <assert.h>
355772Sas200622 #include <string.h>
365772Sas200622 #include <stdlib.h>
375772Sas200622
385772Sas200622 #include <smbsrv/libsmb.h>
395772Sas200622 #include <smbsrv/string.h>
408334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
415772Sas200622
4211447Samw@Sun.COM #define NDR_STRING_MAX 4096
435772Sas200622
445772Sas200622 #define NDR_IS_UNION(T) \
455772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
465772Sas200622 #define NDR_IS_STRING(T) \
475772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
485772Sas200622
498334SJose.Borrego@Sun.COM extern ndr_typeinfo_t ndt_s_wchar;
505772Sas200622
515772Sas200622 /*
525772Sas200622 * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
535772Sas200622 *
545772Sas200622 * Each parameter (call arguments and return values) is a TOP-MOST item.
555772Sas200622 * A TOP-MOST item consists of one or more OUTER items. An OUTER item
565772Sas200622 * consists of one or more INNER items. There are important differences
575772Sas200622 * between each kind, which, primarily, have to do with the allocation
585772Sas200622 * of memory to contain data structures and the order of processing.
595772Sas200622 *
605772Sas200622 * This is most easily demonstrated with a short example.
615772Sas200622 * Consider these structures:
625772Sas200622 *
635772Sas200622 * struct top_param {
645772Sas200622 * long level;
655772Sas200622 * struct list * head;
665772Sas200622 * long count;
675772Sas200622 * };
685772Sas200622 *
695772Sas200622 * struct list {
705772Sas200622 * struct list * next;
715772Sas200622 * char * str; // a string
725772Sas200622 * };
735772Sas200622 *
745772Sas200622 * Now, consider an instance tree like this:
755772Sas200622 *
765772Sas200622 * +---------+ +-------+ +-------+
775772Sas200622 * |top_param| +--->|list #1| +--->|list #2|
785772Sas200622 * +---------+ | +-------+ | +-------+
795772Sas200622 * | level | | | next ----+ | next --->(NULL)
805772Sas200622 * | head ----+ | str -->"foo" | str -->"bar"
815772Sas200622 * | count | | flag | | flag |
825772Sas200622 * +---------+ +-------+ +-------+
835772Sas200622 *
845772Sas200622 * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
855772Sas200622 * The vertical bars (|) indicate OUTER construct boundaries.
865772Sas200622 *
875772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+
885772Sas200622 * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
895772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+
905772Sas200622 * level |<----------------------- head -------------------------->|count
915772Sas200622 * TOP TOP TOP
925772Sas200622 *
935772Sas200622 * Here's what to notice:
945772Sas200622 *
955772Sas200622 * - The members of the TOP-MOST construct are scattered through the Stub
965772Sas200622 * Data in the order they occur. This example shows a TOP-MOST construct
975772Sas200622 * consisting of atomic types (pointers and integers). A construct
985772Sas200622 * (struct) within the TOP-MOST construct would be contiguous and not
995772Sas200622 * scattered.
1005772Sas200622 *
1015772Sas200622 * - The members of OUTER constructs are contiguous, which allows for
1025772Sas200622 * non-copied relocated (fixed-up) data structures at the packet's
1035772Sas200622 * destination. We don't do fix-ups here. The pointers within the
1045772Sas200622 * OUTER constructs are processed depth-first in the order that they
1055772Sas200622 * occur. If they were processed breadth first, the sequence would
1065772Sas200622 * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may
1075772Sas200622 * be variable length, and pointers are often encountered before the
1085772Sas200622 * size(s) is known.
1095772Sas200622 *
1105772Sas200622 * - The INNER constructs are simply the members of an OUTER construct.
1115772Sas200622 *
1125772Sas200622 * For comparison, consider how ONC RPC would handle the same tree of
1135772Sas200622 * data. ONC requires very little buffering, while DCE requires enough
1145772Sas200622 * buffer space for the entire message. ONC does atom-by-atom depth-first
1155772Sas200622 * (de)serialization and copy, while DCE allows for constructs to be
1165772Sas200622 * "fixed-up" (relocated) in place at the destination. The packet data
1175772Sas200622 * for the same tree processed by ONC RPC would look like this:
1185772Sas200622 *
1195772Sas200622 * +---------------------------------------------------------------------+
1205772Sas200622 * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
1215772Sas200622 * +---------------------------------------------------------------------+
1225772Sas200622 * TOP #1 #2 #2 bar #2 #1 foo #1 TOP
1235772Sas200622 *
1245772Sas200622 * More details about each TOP-MOST, OUTER, and INNER constructs appear
1255772Sas200622 * throughout this source file near where such constructs are processed.
1265772Sas200622 *
1275772Sas200622 * NDR_REFERENCE
1285772Sas200622 *
1298334SJose.Borrego@Sun.COM * The primary object for NDR is the ndr_ref_t.
1305772Sas200622 *
1318334SJose.Borrego@Sun.COM * An ndr reference indicates the local datum (i.e. native "C" data
1325772Sas200622 * format), and the element within the Stub Data (contained within the
1338334SJose.Borrego@Sun.COM * RPC PDU (protocol data unit). An ndr reference also indicates,
1345772Sas200622 * largely as a debugging aid, something about the type of the
1355772Sas200622 * element/datum, and the enclosing construct for the element. The
1368334SJose.Borrego@Sun.COM * ndr reference's are typically allocated on the stack as locals,
1378334SJose.Borrego@Sun.COM * and the chain of ndr-reference.enclosing references is in reverse
1385772Sas200622 * order of the call graph.
1395772Sas200622 *
1408334SJose.Borrego@Sun.COM * The ndr-reference.datum is a pointer to the local memory that
1418334SJose.Borrego@Sun.COM * contains/receives the value. The ndr-reference.pdu_offset indicates
1425772Sas200622 * where in the Stub Data the value is to be stored/retrieved.
1435772Sas200622 *
1448334SJose.Borrego@Sun.COM * The ndr-reference also contains various parameters to the NDR
1458334SJose.Borrego@Sun.COM * process, such as ndr-reference.size_is, which indicates the size
1468334SJose.Borrego@Sun.COM * of variable length data, or ndr-reference.switch_is, which
1475772Sas200622 * indicates the arm of a union to use.
1485772Sas200622 *
1495772Sas200622 * QUEUE OF OUTER REFERENCES
1505772Sas200622 *
1515772Sas200622 * Some OUTER constructs are variable size. Sometimes (often) we don't
1525772Sas200622 * know the size of the OUTER construct until after pointers have been
1535772Sas200622 * encountered. Hence, we can not begin processing the referent of the
1545772Sas200622 * pointer until after the referring OUTER construct is completely
1555772Sas200622 * processed, i.e. we don't know where to find/put the referent in the
1565772Sas200622 * Stub Data until we know the size of all its predecessors.
1575772Sas200622 *
1585772Sas200622 * This is managed using the queue of OUTER references. The queue is
1598334SJose.Borrego@Sun.COM * anchored in ndr_stream.outer_queue_head. At any time,
1608334SJose.Borrego@Sun.COM * ndr_stream.outer_queue_tailp indicates where to put the
1618334SJose.Borrego@Sun.COM * ndr-reference for the next encountered pointer.
1625772Sas200622 *
1635772Sas200622 * Refer to the example above as we illustrate the queue here. In these
1645772Sas200622 * illustrations, the queue entries are not the data structures themselves.
1658334SJose.Borrego@Sun.COM * Rather, they are ndr-reference entries which **refer** to the data
1665772Sas200622 * structures in both the PDU and local memory.
1675772Sas200622 *
1685772Sas200622 * During some point in the processing, the queue looks like this:
1695772Sas200622 *
1705772Sas200622 * outer_current -------v
1715772Sas200622 * outer_queue_head --> list#1 --0
1725772Sas200622 * outer_queue_tailp ---------&
1735772Sas200622 *
1745772Sas200622 * When the pointer #1.next is encountered, and entry is added to the
1755772Sas200622 * queue,
1765772Sas200622 *
1775772Sas200622 * outer_current -------v
1785772Sas200622 * outer_queue_head --> list#1 --> list#2 --0
1795772Sas200622 * outer_queue_tailp --------------------&
1805772Sas200622 *
1815772Sas200622 * and the members of #1 continue to be processed, which encounters
1825772Sas200622 * #1.str:
1835772Sas200622 *
1845772Sas200622 * outer_current -------v
1855772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
1865772Sas200622 * outer_queue_tailp ------------------------------&
1875772Sas200622 *
1888334SJose.Borrego@Sun.COM * Upon the completion of list#1, the processing continues by moving to
1898334SJose.Borrego@Sun.COM * ndr_stream.outer_current->next, and the tail is set to this outer member:
1905772Sas200622 *
1915772Sas200622 * outer_current ------------------v
1925772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
1935772Sas200622 * outer_queue_tailp --------------------&
1945772Sas200622 *
1955772Sas200622 * Space for list#2 is allocated, either in the Stub Data or of local
1965772Sas200622 * memory. When #2.next is encountered, it is found to be the null
1975772Sas200622 * pointer and no reference is added to the queue. When #2.str is
1985772Sas200622 * encountered, it is found to be valid, and a reference is added:
1995772Sas200622 *
2005772Sas200622 * outer_current ------------------v
2015772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
2025772Sas200622 * outer_queue_tailp ------------------------------&
2035772Sas200622 *
2045772Sas200622 * Processing continues in a similar fashion with the string "bar",
2055772Sas200622 * which is variable-length. At this point, memory for "bar" may be
2065772Sas200622 * malloc()ed during NDR_M_OP_UNMARSHALL:
2075772Sas200622 *
2085772Sas200622 * outer_current -----------------------------v
2095772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
2105772Sas200622 * outer_queue_tailp ------------------------------&
2115772Sas200622 *
2125772Sas200622 * And finishes on string "foo". Notice that because "bar" is a
2135772Sas200622 * variable length string, and we don't know the PDU offset for "foo"
2145772Sas200622 * until we reach this point.
2155772Sas200622 *
2165772Sas200622 * When the queue is drained (current->next==0), processing continues
2175772Sas200622 * with the next TOP-MOST member.
2185772Sas200622 *
2195772Sas200622 * The queue of OUTER constructs manages the variable-length semantics
2205772Sas200622 * of OUTER constructs and satisfies the depth-first requirement.
2215772Sas200622 * We allow the queue to linger until the entire TOP-MOST structure is
2225772Sas200622 * processed as an aid to debugging.
2235772Sas200622 */
2245772Sas200622
2258334SJose.Borrego@Sun.COM static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
2268334SJose.Borrego@Sun.COM extern int ndr__ulong(ndr_ref_t *);
2275772Sas200622
2285772Sas200622 /*
2295772Sas200622 * TOP-MOST ELEMENTS
2305772Sas200622 *
2315772Sas200622 * This is fundamentally the first OUTER construct of the parameter,
2325772Sas200622 * possibly followed by more OUTER constructs due to pointers. The
2335772Sas200622 * datum (local memory) for TOP-MOST constructs (structs) is allocated
2345772Sas200622 * by the caller of NDR.
2355772Sas200622 *
2365772Sas200622 * After the element is transferred, the outer_queue is drained.
2375772Sas200622 *
2385772Sas200622 * All we have to do is add an entry to the outer_queue for this
2395772Sas200622 * top-most member, and commence the outer_queue processing.
2405772Sas200622 */
2415772Sas200622 int
ndo_process(ndr_stream_t * nds,ndr_typeinfo_t * ti,char * datum)2428334SJose.Borrego@Sun.COM ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
2435772Sas200622 {
2448334SJose.Borrego@Sun.COM ndr_ref_t myref;
2455772Sas200622
2465772Sas200622 bzero(&myref, sizeof (myref));
2478334SJose.Borrego@Sun.COM myref.stream = nds;
2485772Sas200622 myref.datum = datum;
2495772Sas200622 myref.name = "PROCESS";
2505772Sas200622 myref.ti = ti;
2515772Sas200622
2528334SJose.Borrego@Sun.COM return (ndr_topmost(&myref));
2535772Sas200622 }
2545772Sas200622
2555772Sas200622 int
ndo_operation(ndr_stream_t * nds,ndr_typeinfo_t * ti,int opnum,char * datum)2568334SJose.Borrego@Sun.COM ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
2575772Sas200622 {
2588334SJose.Borrego@Sun.COM ndr_ref_t myref;
2595772Sas200622
2605772Sas200622 bzero(&myref, sizeof (myref));
2618334SJose.Borrego@Sun.COM myref.stream = nds;
2625772Sas200622 myref.datum = datum;
2635772Sas200622 myref.name = "OPERATION";
2645772Sas200622 myref.ti = ti;
2655772Sas200622 myref.inner_flags = NDR_F_SWITCH_IS;
2665772Sas200622 myref.switch_is = opnum;
2675772Sas200622
2685772Sas200622 if (ti->type_flags != NDR_F_INTERFACE) {
2695772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
2705772Sas200622 return (0);
2715772Sas200622 }
2725772Sas200622
2735772Sas200622 return ((*ti->ndr_func)(&myref));
2745772Sas200622 }
2755772Sas200622
2765772Sas200622 int
ndr_params(ndr_ref_t * params_ref)2778334SJose.Borrego@Sun.COM ndr_params(ndr_ref_t *params_ref)
2785772Sas200622 {
2798334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = params_ref->ti;
2805772Sas200622
2815772Sas200622 if (ti->type_flags == NDR_F_OPERATION)
2825772Sas200622 return (*ti->ndr_func) (params_ref);
2835772Sas200622 else
2848334SJose.Borrego@Sun.COM return (ndr_topmost(params_ref));
2855772Sas200622 }
2865772Sas200622
2875772Sas200622 int
ndr_topmost(ndr_ref_t * top_ref)2888334SJose.Borrego@Sun.COM ndr_topmost(ndr_ref_t *top_ref)
2895772Sas200622 {
2908334SJose.Borrego@Sun.COM ndr_stream_t *nds;
2918334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti;
2928334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref = 0;
2935772Sas200622 int is_varlen;
2945772Sas200622 int is_string;
2955772Sas200622 int error;
2965772Sas200622 int rc;
2975772Sas200622 unsigned n_fixed;
2985772Sas200622 int params;
2995772Sas200622
3005772Sas200622 assert(top_ref);
3015772Sas200622 assert(top_ref->stream);
3025772Sas200622 assert(top_ref->ti);
3035772Sas200622
3048334SJose.Borrego@Sun.COM nds = top_ref->stream;
3055772Sas200622 ti = top_ref->ti;
3065772Sas200622
3075772Sas200622 is_varlen = ti->pdu_size_variable_part;
3085772Sas200622 is_string = NDR_IS_STRING(ti);
3095772Sas200622
3108334SJose.Borrego@Sun.COM assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
3118334SJose.Borrego@Sun.COM assert(!nds->outer_current);
3125772Sas200622
3135772Sas200622 params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
3145772Sas200622
3155772Sas200622 switch (params) {
3165772Sas200622 case NDR_F_NONE:
3175772Sas200622 case NDR_F_SWITCH_IS:
3185772Sas200622 if (is_string || is_varlen) {
3195772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
3205772Sas200622 NDR_SET_ERROR(outer_ref, error);
3215772Sas200622 return (0);
3225772Sas200622 }
3235772Sas200622 n_fixed = ti->pdu_size_fixed_part;
3245772Sas200622 break;
3255772Sas200622
3265772Sas200622 case NDR_F_SIZE_IS:
3275772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
3285772Sas200622 NDR_SET_ERROR(outer_ref, error);
3295772Sas200622 return (0);
3305772Sas200622
3315772Sas200622 case NDR_F_DIMENSION_IS:
3325772Sas200622 if (is_varlen) {
3335772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
3345772Sas200622 NDR_SET_ERROR(outer_ref, error);
3355772Sas200622 return (0);
3365772Sas200622 }
3375772Sas200622 n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
3385772Sas200622 break;
3395772Sas200622
3405772Sas200622 case NDR_F_IS_POINTER:
3415772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
3425772Sas200622 n_fixed = 4;
3435772Sas200622 break;
3445772Sas200622
3455772Sas200622 case NDR_F_IS_REFERENCE:
3465772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
3475772Sas200622 n_fixed = 0;
3485772Sas200622 break;
3495772Sas200622
3505772Sas200622 default:
3515772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD;
3525772Sas200622 NDR_SET_ERROR(outer_ref, error);
3535772Sas200622 return (0);
3545772Sas200622 }
3555772Sas200622
3568334SJose.Borrego@Sun.COM outer_ref = ndr_enter_outer_queue(top_ref);
3575772Sas200622 if (!outer_ref)
3585772Sas200622 return (0); /* error already set */
3595772Sas200622
3605772Sas200622 /*
3615772Sas200622 * Hand-craft the first OUTER construct and directly call
3628334SJose.Borrego@Sun.COM * ndr_inner(). Then, run the outer_queue. We do this
3638334SJose.Borrego@Sun.COM * because ndr_outer() wants to malloc() memory for
3645772Sas200622 * the construct, and we already have the memory.
3655772Sas200622 */
3665772Sas200622
3675772Sas200622 /* move the flags, etc, around again, undoes enter_outer_queue() */
3685772Sas200622 outer_ref->inner_flags = top_ref->inner_flags;
3695772Sas200622 outer_ref->outer_flags = 0;
3705772Sas200622 outer_ref->datum = top_ref->datum;
3715772Sas200622
3725772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */
3738334SJose.Borrego@Sun.COM if (!ndr_outer_align(outer_ref))
3745772Sas200622 return (0); /* error already set */
3755772Sas200622
3765772Sas200622 /* Regardless of what it is, this is where it starts */
3778334SJose.Borrego@Sun.COM outer_ref->pdu_offset = nds->pdu_scan_offset;
3785772Sas200622
3798334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_fixed);
3805772Sas200622 if (!rc)
3815772Sas200622 return (0); /* error already set */
3825772Sas200622
3835772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
3845772Sas200622
3855772Sas200622 /* set-up outer_current, as though run_outer_queue() was doing it */
3868334SJose.Borrego@Sun.COM nds->outer_current = outer_ref;
3878334SJose.Borrego@Sun.COM nds->outer_queue_tailp = &nds->outer_current->next;
3888334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
3895772Sas200622
3905772Sas200622 /* do the topmost member */
3918334SJose.Borrego@Sun.COM rc = ndr_inner(outer_ref);
3925772Sas200622 if (!rc)
3935772Sas200622 return (0); /* error already set */
3945772Sas200622
3958334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
3965772Sas200622
3975772Sas200622 /* advance, as though run_outer_queue() was doing it */
3988334SJose.Borrego@Sun.COM nds->outer_current = nds->outer_current->next;
3998334SJose.Borrego@Sun.COM return (ndr_run_outer_queue(nds));
4005772Sas200622 }
4015772Sas200622
4028334SJose.Borrego@Sun.COM static ndr_ref_t *
ndr_enter_outer_queue(ndr_ref_t * arg_ref)4038334SJose.Borrego@Sun.COM ndr_enter_outer_queue(ndr_ref_t *arg_ref)
4045772Sas200622 {
4058334SJose.Borrego@Sun.COM ndr_stream_t *nds = arg_ref->stream;
4068334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref;
4075772Sas200622
4085772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/
4098334SJose.Borrego@Sun.COM outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
4105772Sas200622 if (!outer_ref) {
4115772Sas200622 NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
4125772Sas200622 return (0);
4135772Sas200622 }
4145772Sas200622
4155772Sas200622 *outer_ref = *arg_ref;
4165772Sas200622
4175772Sas200622 /* move advice in inner_flags to outer_flags */
4185772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
4195772Sas200622 outer_ref->inner_flags = 0;
4208334SJose.Borrego@Sun.COM outer_ref->enclosing = nds->outer_current;
4215772Sas200622 outer_ref->backptr = 0;
4225772Sas200622 outer_ref->datum = 0;
4235772Sas200622
4248334SJose.Borrego@Sun.COM assert(nds->outer_queue_tailp);
4255772Sas200622
4268334SJose.Borrego@Sun.COM outer_ref->next = *nds->outer_queue_tailp;
4278334SJose.Borrego@Sun.COM *nds->outer_queue_tailp = outer_ref;
4288334SJose.Borrego@Sun.COM nds->outer_queue_tailp = &outer_ref->next;
4295772Sas200622 return (outer_ref);
4305772Sas200622 }
4315772Sas200622
4325772Sas200622 int
ndr_run_outer_queue(ndr_stream_t * nds)4338334SJose.Borrego@Sun.COM ndr_run_outer_queue(ndr_stream_t *nds)
4345772Sas200622 {
4358334SJose.Borrego@Sun.COM while (nds->outer_current) {
4368334SJose.Borrego@Sun.COM nds->outer_queue_tailp = &nds->outer_current->next;
4375772Sas200622
4388334SJose.Borrego@Sun.COM if (!ndr_outer(nds->outer_current))
4395772Sas200622 return (0);
4405772Sas200622
4418334SJose.Borrego@Sun.COM nds->outer_current = nds->outer_current->next;
4425772Sas200622 }
4435772Sas200622
4445772Sas200622 return (1);
4455772Sas200622 }
4465772Sas200622
4475772Sas200622 /*
4485772Sas200622 * OUTER CONSTRUCTS
4495772Sas200622 *
4505772Sas200622 * OUTER constructs are where the real work is, which stems from the
4515772Sas200622 * variable-length potential.
4525772Sas200622 *
4535772Sas200622 * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
4545772Sas200622 *
4555772Sas200622 * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
4565772Sas200622 * VARYING, and VARYING/CONFORMANT.
4575772Sas200622 *
4585772Sas200622 * What makes this so tough is that the variable-length array may be well
4595772Sas200622 * encapsulated within the outer construct. Further, because DCE(MS)/RPC
4605772Sas200622 * tries to keep the constructs contiguous in the data stream, the sizing
4615772Sas200622 * information precedes the entire OUTER construct. The sizing information
4625772Sas200622 * must be used at the appropriate time, which can be after many, many,
4635772Sas200622 * many fixed-length elements. During IDL type analysis, we know in
4645772Sas200622 * advance constructs that encapsulate variable-length constructs. So,
4655772Sas200622 * we know when we have a sizing header and when we don't. The actual
4665772Sas200622 * semantics of the header are largely deferred.
4675772Sas200622 *
4685772Sas200622 * Currently, VARYING constructs are not implemented but they are described
4695772Sas200622 * here in case they have to be implemented in the future. Similarly,
4705772Sas200622 * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently
4715772Sas200622 * not implemented. Only one-dimensional, variable-length arrays are
4725772Sas200622 * supported.
4735772Sas200622 *
4745772Sas200622 * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
4755772Sas200622 *
4765772Sas200622 * All variable-length values are arrays. These arrays may be embedded
4775772Sas200622 * well within another construct. However, a variable-length construct
4785772Sas200622 * may ONLY appear as the last member of an enclosing construct. Example:
4795772Sas200622 *
4805772Sas200622 * struct credentials {
4815772Sas200622 * ulong uid, gid;
4825772Sas200622 * ulong n_gids;
4835772Sas200622 * [size_is(n_gids)]
4845772Sas200622 * ulong gids[*]; // variable-length.
4855772Sas200622 * };
4865772Sas200622 *
4875772Sas200622 * CONFORMANT constructs have a dynamic size in local memory and in the
4885772Sas200622 * PDU. The CONFORMANT quality is indicated by the [size_is()] advice.
4895772Sas200622 * CONFORMANT constructs have the following header:
4905772Sas200622 *
4915772Sas200622 * struct conformant_header {
4925772Sas200622 * ulong size_is;
4935772Sas200622 * };
4945772Sas200622 *
4955772Sas200622 * (Multi-dimensional CONFORMANT arrays have a similar header for each
4965772Sas200622 * dimension - not implemented).
4975772Sas200622 *
4985772Sas200622 * Example CONFORMANT construct:
4995772Sas200622 *
5005772Sas200622 * struct user {
5015772Sas200622 * char * name;
5025772Sas200622 * struct credentials cred; // see above
5035772Sas200622 * };
5045772Sas200622 *
5055772Sas200622 * Consider the data tree:
5065772Sas200622 *
5075772Sas200622 * +--------+
5085772Sas200622 * | user |
5095772Sas200622 * +--------+
5105772Sas200622 * | name ----> "fred" (the string is a different OUTER)
5115772Sas200622 * | uid |
5125772Sas200622 * | gid |
5135772Sas200622 * | n_gids | for example, 3
5145772Sas200622 * | gids[0]|
5155772Sas200622 * | gids[1]|
5165772Sas200622 * | gids[2]|
5175772Sas200622 * +--------+
5185772Sas200622 *
5195772Sas200622 * The OUTER construct in the Stub Data would be:
5205772Sas200622 *
5215772Sas200622 * +---+---------+---------------------------------------------+
5225772Sas200622 * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]|
5235772Sas200622 * +---+---------+---------------------------------------------+
5245772Sas200622 * szing hdr|user |<-------------- user.cred ------------>|
5255772Sas200622 * |<--- fixed-size ---->|<----- conformant ---->|
5265772Sas200622 *
5275772Sas200622 * The ndr_typeinfo for struct user will have:
5285772Sas200622 * pdu_fixed_size_part = 16 four long words (name uid gid n_gids)
5295772Sas200622 * pdu_variable_size_part = 4 per element, sizeof gids[0]
5305772Sas200622 *
5315772Sas200622 * VARYING CONSTRUCTS -- NOT IMPLEMENTED
5325772Sas200622 *
5335772Sas200622 * VARYING constructs have the following header:
5345772Sas200622 *
5355772Sas200622 * struct varying_header {
5365772Sas200622 * ulong first_is;
5375772Sas200622 * ulong length_is;
5385772Sas200622 * };
5395772Sas200622 *
5405772Sas200622 * This indicates which interval of an array is significant.
5415772Sas200622 * Non-intersecting elements of the array are undefined and usually
5425772Sas200622 * zero-filled. The first_is parameter for C arrays is always 0 for
5435772Sas200622 * the first element.
5445772Sas200622 *
5455772Sas200622 * N.B. Constructs may contain one CONFORMANT element, which is always
5465772Sas200622 * last, but may contain many VARYING elements, which can be anywhere.
5475772Sas200622 *
5485772Sas200622 * VARYING CONFORMANT constructs have the sizing headers arranged like
5495772Sas200622 * this:
5505772Sas200622 *
5515772Sas200622 * struct conformant_header all_conformant[N_CONFORMANT_DIM];
5525772Sas200622 * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS];
5535772Sas200622 *
5545772Sas200622 * The sizing header is immediately followed by the values for the
5555772Sas200622 * construct. Again, we don't support more than one dimension and
5565772Sas200622 * we don't support VARYING constructs at this time.
5575772Sas200622 *
5585772Sas200622 * A good example of a VARYING/CONFORMANT data structure is the UNIX
5595772Sas200622 * directory entry:
5605772Sas200622 *
5615772Sas200622 * struct dirent {
5625772Sas200622 * ushort reclen;
5635772Sas200622 * ushort namlen;
5645772Sas200622 * ulong inum;
5655772Sas200622 * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL
5665772Sas200622 * uchar name[*];
5675772Sas200622 * };
5685772Sas200622 *
5695772Sas200622 *
5705772Sas200622 * STRINGS ARE A SPECIAL CASE
5715772Sas200622 *
5725772Sas200622 * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures
5735772Sas200622 * for strings. This is a simple one-dimensional variable-length array,
5745772Sas200622 * typically with its last element all zeroes. We handle strings with the
5755772Sas200622 * header:
5765772Sas200622 *
5775772Sas200622 * struct string_header {
5785772Sas200622 * ulong size_is;
5795772Sas200622 * ulong first_is; // always 0
5805772Sas200622 * ulong length_is; // always same as size_is
5815772Sas200622 * };
5825772Sas200622 *
5835772Sas200622 * If general support for VARYING and VARYING/CONFORMANT mechanisms is
5845772Sas200622 * implemented, we probably won't need the strings special case.
5855772Sas200622 */
5865772Sas200622 int
ndr_outer(ndr_ref_t * outer_ref)5878334SJose.Borrego@Sun.COM ndr_outer(ndr_ref_t *outer_ref)
5885772Sas200622 {
5898334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
5908334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
5915772Sas200622 int is_varlen = ti->pdu_size_variable_part;
5925772Sas200622 int is_union = NDR_IS_UNION(ti);
5935772Sas200622 int is_string = NDR_IS_STRING(ti);
5945772Sas200622 int error = NDR_ERR_OUTER_PARAMS_BAD;
5955772Sas200622 int params;
5965772Sas200622
5975772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
5985772Sas200622
5995772Sas200622 NDR_TATTLE(outer_ref, "--OUTER--");
6005772Sas200622
6015772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */
6028334SJose.Borrego@Sun.COM if (!ndr_outer_align(outer_ref))
6035772Sas200622 return (0); /* error already set */
6045772Sas200622
6055772Sas200622 /* Regardless of what it is, this is where it starts */
6068334SJose.Borrego@Sun.COM outer_ref->pdu_offset = nds->pdu_scan_offset;
6075772Sas200622
6085772Sas200622 if (is_union) {
6095772Sas200622 error = NDR_ERR_OUTER_UNION_ILLEGAL;
6105772Sas200622 NDR_SET_ERROR(outer_ref, error);
6115772Sas200622 return (0);
6125772Sas200622 }
6135772Sas200622
6145772Sas200622 switch (params) {
6155772Sas200622 case NDR_F_NONE:
6165772Sas200622 if (is_string)
6178334SJose.Borrego@Sun.COM return (ndr_outer_string(outer_ref));
6185772Sas200622 if (is_varlen)
6198334SJose.Borrego@Sun.COM return (ndr_outer_conformant_construct(outer_ref));
6205772Sas200622
6218334SJose.Borrego@Sun.COM return (ndr_outer_fixed(outer_ref));
6225772Sas200622 break;
6235772Sas200622
6245772Sas200622 case NDR_F_SIZE_IS:
6255772Sas200622 case NDR_F_DIMENSION_IS:
62611447Samw@Sun.COM case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
62711447Samw@Sun.COM case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
6285772Sas200622 if (is_varlen) {
6295772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
6305772Sas200622 break;
6315772Sas200622 }
6325772Sas200622
63311447Samw@Sun.COM if (params & NDR_F_SIZE_IS)
6348334SJose.Borrego@Sun.COM return (ndr_outer_conformant_array(outer_ref));
6355772Sas200622 else
6368334SJose.Borrego@Sun.COM return (ndr_outer_fixed_array(outer_ref));
6375772Sas200622 break;
6385772Sas200622
6395772Sas200622 default:
6405772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD;
6415772Sas200622 break;
6425772Sas200622 }
6435772Sas200622
6445772Sas200622 /*
6455772Sas200622 * If we get here, something is wrong. Most likely,
6465772Sas200622 * the params flags do not match.
6475772Sas200622 */
6485772Sas200622 NDR_SET_ERROR(outer_ref, error);
6495772Sas200622 return (0);
6505772Sas200622 }
6515772Sas200622
6525772Sas200622 int
ndr_outer_fixed(ndr_ref_t * outer_ref)6538334SJose.Borrego@Sun.COM ndr_outer_fixed(ndr_ref_t *outer_ref)
6545772Sas200622 {
6558334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
6568334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
6578334SJose.Borrego@Sun.COM ndr_ref_t myref;
6585772Sas200622 char *valp = NULL;
6595772Sas200622 int is_varlen = ti->pdu_size_variable_part;
6605772Sas200622 int is_union = NDR_IS_UNION(ti);
6615772Sas200622 int is_string = NDR_IS_STRING(ti);
6625772Sas200622 int rc;
6635772Sas200622 unsigned n_hdr;
6645772Sas200622 unsigned n_fixed;
6655772Sas200622 unsigned n_variable;
6665772Sas200622 unsigned n_alloc;
6675772Sas200622 unsigned n_pdu_total;
6685772Sas200622 int params;
6695772Sas200622
6705772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
6715772Sas200622
6725772Sas200622 assert(!is_varlen && !is_string && !is_union);
6735772Sas200622 assert(params == NDR_F_NONE);
6745772Sas200622
6755772Sas200622 /* no header for this */
6765772Sas200622 n_hdr = 0;
6775772Sas200622
6785772Sas200622 /* fixed part -- exactly one of these */
6795772Sas200622 n_fixed = ti->pdu_size_fixed_part;
6805772Sas200622 assert(n_fixed > 0);
6815772Sas200622
6825772Sas200622 /* variable part -- exactly none of these */
6835772Sas200622 n_variable = 0;
6845772Sas200622
6855772Sas200622 /* sum them up to determine the PDU space required */
6865772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
6875772Sas200622
6885772Sas200622 /* similar sum to determine how much local memory is required */
6895772Sas200622 n_alloc = n_fixed + n_variable;
6905772Sas200622
6918334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
6925772Sas200622 if (!rc)
6935772Sas200622 return (rc); /* error already set */
6945772Sas200622
6958334SJose.Borrego@Sun.COM switch (nds->m_op) {
6965772Sas200622 case NDR_M_OP_MARSHALL:
6975772Sas200622 valp = outer_ref->datum;
698*11633SJoyce.McIntosh@Sun.COM if (!valp) {
699*11633SJoyce.McIntosh@Sun.COM NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
700*11633SJoyce.McIntosh@Sun.COM return (0);
701*11633SJoyce.McIntosh@Sun.COM }
70211447Samw@Sun.COM if (outer_ref->backptr)
7035772Sas200622 assert(valp == *outer_ref->backptr);
7045772Sas200622 break;
7055772Sas200622
7065772Sas200622 case NDR_M_OP_UNMARSHALL:
7078334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref);
7085772Sas200622 if (!valp) {
7095772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
7105772Sas200622 return (0);
7115772Sas200622 }
7125772Sas200622 if (outer_ref->backptr)
7135772Sas200622 *outer_ref->backptr = valp;
7145772Sas200622 outer_ref->datum = valp;
7155772Sas200622 break;
7165772Sas200622
7175772Sas200622 default:
7185772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
7195772Sas200622 return (0);
7205772Sas200622 }
7215772Sas200622
7225772Sas200622 bzero(&myref, sizeof (myref));
7238334SJose.Borrego@Sun.COM myref.stream = nds;
7245772Sas200622 myref.enclosing = outer_ref;
7255772Sas200622 myref.ti = outer_ref->ti;
7265772Sas200622 myref.datum = outer_ref->datum;
7275772Sas200622 myref.name = "FIXED-VALUE";
7285772Sas200622 myref.outer_flags = NDR_F_NONE;
7295772Sas200622 myref.inner_flags = NDR_F_NONE;
7305772Sas200622
7315772Sas200622 myref.pdu_offset = outer_ref->pdu_offset;
7325772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
7335772Sas200622
7348334SJose.Borrego@Sun.COM rc = ndr_inner(&myref);
7355772Sas200622 if (!rc)
7365772Sas200622 return (rc); /* error already set */
7375772Sas200622
7388334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
7395772Sas200622 return (1);
7405772Sas200622 }
7415772Sas200622
7425772Sas200622 int
ndr_outer_fixed_array(ndr_ref_t * outer_ref)7438334SJose.Borrego@Sun.COM ndr_outer_fixed_array(ndr_ref_t *outer_ref)
7445772Sas200622 {
7458334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
7468334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
7478334SJose.Borrego@Sun.COM ndr_ref_t myref;
7485772Sas200622 char *valp = NULL;
7495772Sas200622 int is_varlen = ti->pdu_size_variable_part;
7505772Sas200622 int is_union = NDR_IS_UNION(ti);
7515772Sas200622 int is_string = NDR_IS_STRING(ti);
7525772Sas200622 int rc;
7535772Sas200622 unsigned n_hdr;
7545772Sas200622 unsigned n_fixed;
7555772Sas200622 unsigned n_variable;
7565772Sas200622 unsigned n_alloc;
7575772Sas200622 unsigned n_pdu_total;
7585772Sas200622 int params;
7595772Sas200622
7605772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
7615772Sas200622
7625772Sas200622 assert(!is_varlen && !is_string && !is_union);
7635772Sas200622 assert(params == NDR_F_DIMENSION_IS);
7645772Sas200622
7655772Sas200622 /* no header for this */
7665772Sas200622 n_hdr = 0;
7675772Sas200622
7685772Sas200622 /* fixed part -- exactly dimension_is of these */
7695772Sas200622 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
7705772Sas200622 assert(n_fixed > 0);
7715772Sas200622
7725772Sas200622 /* variable part -- exactly none of these */
7735772Sas200622 n_variable = 0;
7745772Sas200622
7755772Sas200622 /* sum them up to determine the PDU space required */
7765772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
7775772Sas200622
7785772Sas200622 /* similar sum to determine how much local memory is required */
7795772Sas200622 n_alloc = n_fixed + n_variable;
7805772Sas200622
7818334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
7825772Sas200622 if (!rc)
7835772Sas200622 return (rc); /* error already set */
7845772Sas200622
7858334SJose.Borrego@Sun.COM switch (nds->m_op) {
7865772Sas200622 case NDR_M_OP_MARSHALL:
7875772Sas200622 valp = outer_ref->datum;
788*11633SJoyce.McIntosh@Sun.COM if (!valp) {
789*11633SJoyce.McIntosh@Sun.COM NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
790*11633SJoyce.McIntosh@Sun.COM return (0);
791*11633SJoyce.McIntosh@Sun.COM }
79211447Samw@Sun.COM if (outer_ref->backptr)
7935772Sas200622 assert(valp == *outer_ref->backptr);
7945772Sas200622 break;
7955772Sas200622
7965772Sas200622 case NDR_M_OP_UNMARSHALL:
7978334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref);
7985772Sas200622 if (!valp) {
7995772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
8005772Sas200622 return (0);
8015772Sas200622 }
8025772Sas200622 if (outer_ref->backptr)
8035772Sas200622 *outer_ref->backptr = valp;
8045772Sas200622 outer_ref->datum = valp;
8055772Sas200622 break;
8065772Sas200622
8075772Sas200622 default:
8085772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
8095772Sas200622 return (0);
8105772Sas200622 }
8115772Sas200622
8125772Sas200622 bzero(&myref, sizeof (myref));
8138334SJose.Borrego@Sun.COM myref.stream = nds;
8145772Sas200622 myref.enclosing = outer_ref;
8155772Sas200622 myref.ti = outer_ref->ti;
8165772Sas200622 myref.datum = outer_ref->datum;
8175772Sas200622 myref.name = "FIXED-ARRAY";
8185772Sas200622 myref.outer_flags = NDR_F_NONE;
8195772Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS;
8205772Sas200622 myref.dimension_is = outer_ref->dimension_is;
8215772Sas200622
8225772Sas200622 myref.pdu_offset = outer_ref->pdu_offset;
8235772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
8245772Sas200622
8258334SJose.Borrego@Sun.COM rc = ndr_inner(&myref);
8265772Sas200622 if (!rc)
8275772Sas200622 return (rc); /* error already set */
8285772Sas200622
8298334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
8305772Sas200622 return (1);
8315772Sas200622 }
8325772Sas200622
8335772Sas200622 int
ndr_outer_conformant_array(ndr_ref_t * outer_ref)8348334SJose.Borrego@Sun.COM ndr_outer_conformant_array(ndr_ref_t *outer_ref)
8355772Sas200622 {
8368334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
8378334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
8388334SJose.Borrego@Sun.COM ndr_ref_t myref;
8395772Sas200622 char *valp = NULL;
8405772Sas200622 int is_varlen = ti->pdu_size_variable_part;
8415772Sas200622 int is_union = NDR_IS_UNION(ti);
8425772Sas200622 int is_string = NDR_IS_STRING(ti);
8435772Sas200622 unsigned long size_is;
8445772Sas200622 int rc;
8455772Sas200622 unsigned n_hdr;
8465772Sas200622 unsigned n_fixed;
8475772Sas200622 unsigned n_variable;
8485772Sas200622 unsigned n_alloc;
8495772Sas200622 unsigned n_pdu_total;
85011447Samw@Sun.COM unsigned n_ptr_offset;
8515772Sas200622 int params;
8525772Sas200622
8535772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
8545772Sas200622
8555772Sas200622 assert(!is_varlen && !is_string && !is_union);
85611447Samw@Sun.COM assert(params & NDR_F_SIZE_IS);
8575772Sas200622
8585772Sas200622 /* conformant header for this */
8595772Sas200622 n_hdr = 4;
8605772Sas200622
8615772Sas200622 /* fixed part -- exactly none of these */
8625772Sas200622 n_fixed = 0;
8635772Sas200622
8645772Sas200622 /* variable part -- exactly size_of of these */
8655772Sas200622 /* notice that it is the **fixed** size of the ti */
8665772Sas200622 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
8675772Sas200622
8685772Sas200622 /* sum them up to determine the PDU space required */
8695772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
8705772Sas200622
8715772Sas200622 /* similar sum to determine how much local memory is required */
8725772Sas200622 n_alloc = n_fixed + n_variable;
8735772Sas200622
8748334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
8755772Sas200622 if (!rc)
8765772Sas200622 return (rc); /* error already set */
8775772Sas200622
8788334SJose.Borrego@Sun.COM switch (nds->m_op) {
8795772Sas200622 case NDR_M_OP_MARSHALL:
8805772Sas200622 size_is = outer_ref->size_is;
8818334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
8825772Sas200622 if (!rc)
8835772Sas200622 return (0); /* error already set */
8845772Sas200622
8855772Sas200622 valp = outer_ref->datum;
886*11633SJoyce.McIntosh@Sun.COM if (!valp) {
887*11633SJoyce.McIntosh@Sun.COM NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
888*11633SJoyce.McIntosh@Sun.COM return (0);
889*11633SJoyce.McIntosh@Sun.COM }
89011447Samw@Sun.COM if (outer_ref->backptr)
8915772Sas200622 assert(valp == *outer_ref->backptr);
89211447Samw@Sun.COM n_ptr_offset = 4;
8935772Sas200622 break;
8945772Sas200622
8955772Sas200622 case NDR_M_OP_UNMARSHALL:
89611447Samw@Sun.COM if (params & NDR_F_IS_REFERENCE) {
89711447Samw@Sun.COM size_is = outer_ref->size_is;
89811447Samw@Sun.COM n_ptr_offset = 0;
89911447Samw@Sun.COM } else {
90011447Samw@Sun.COM /* NDR_F_IS_POINTER */
90111447Samw@Sun.COM rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
90211447Samw@Sun.COM if (!rc)
90311447Samw@Sun.COM return (0); /* error already set */
9045772Sas200622
90511447Samw@Sun.COM if (size_is != outer_ref->size_is) {
90611447Samw@Sun.COM NDR_SET_ERROR(outer_ref,
90711447Samw@Sun.COM NDR_ERR_SIZE_IS_MISMATCH_PDU);
90811447Samw@Sun.COM return (0);
90911447Samw@Sun.COM }
91011447Samw@Sun.COM
91111447Samw@Sun.COM n_ptr_offset = 4;
9125772Sas200622 }
9135772Sas200622
9146771Sjb150015 if (size_is > 0) {
9158334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref);
9166771Sjb150015 if (!valp) {
9176771Sjb150015 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
9186771Sjb150015 return (0);
9196771Sjb150015 }
9205772Sas200622 }
9216771Sjb150015
9225772Sas200622 if (outer_ref->backptr)
9235772Sas200622 *outer_ref->backptr = valp;
9245772Sas200622 outer_ref->datum = valp;
9255772Sas200622 break;
9265772Sas200622
9275772Sas200622 default:
9285772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
9295772Sas200622 return (0);
9305772Sas200622 }
9315772Sas200622
9325772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
9335772Sas200622 outer_ref->type_flags = NDR_F_NONE;
9345772Sas200622 outer_ref->inner_flags = NDR_F_NONE;
9355772Sas200622
9366771Sjb150015 if (size_is > 0) {
9376771Sjb150015 bzero(&myref, sizeof (myref));
9388334SJose.Borrego@Sun.COM myref.stream = nds;
9396771Sjb150015 myref.enclosing = outer_ref;
9406771Sjb150015 myref.ti = outer_ref->ti;
9416771Sjb150015 myref.datum = outer_ref->datum;
9426771Sjb150015 myref.name = "CONFORMANT-ARRAY";
9436771Sjb150015 myref.outer_flags = NDR_F_NONE;
9446771Sjb150015 myref.inner_flags = NDR_F_SIZE_IS;
9456771Sjb150015 myref.size_is = outer_ref->size_is;
9466771Sjb150015
9476771Sjb150015 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */
9486771Sjb150015 myref.dimension_is = outer_ref->size_is; /* convenient */
9496771Sjb150015
95011447Samw@Sun.COM myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
9516771Sjb150015
9528334SJose.Borrego@Sun.COM rc = ndr_inner(&myref);
9536771Sjb150015 if (!rc)
9546771Sjb150015 return (rc); /* error already set */
9556771Sjb150015 }
9565772Sas200622
9578334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
9585772Sas200622 return (1);
9595772Sas200622 }
9605772Sas200622
9615772Sas200622 int
ndr_outer_conformant_construct(ndr_ref_t * outer_ref)9628334SJose.Borrego@Sun.COM ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
9635772Sas200622 {
9648334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
9658334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
9668334SJose.Borrego@Sun.COM ndr_ref_t myref;
9675772Sas200622 char *valp = NULL;
9685772Sas200622 int is_varlen = ti->pdu_size_variable_part;
9695772Sas200622 int is_union = NDR_IS_UNION(ti);
9705772Sas200622 int is_string = NDR_IS_STRING(ti);
9715772Sas200622 unsigned long size_is;
9725772Sas200622 int rc;
9735772Sas200622 unsigned n_hdr;
9745772Sas200622 unsigned n_fixed;
9755772Sas200622 unsigned n_variable;
9765772Sas200622 unsigned n_alloc;
9775772Sas200622 unsigned n_pdu_total;
9785772Sas200622 int params;
9795772Sas200622
9805772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
9815772Sas200622
9825772Sas200622 assert(is_varlen && !is_string && !is_union);
9835772Sas200622 assert(params == NDR_F_NONE);
9845772Sas200622
9855772Sas200622 /* conformant header for this */
9865772Sas200622 n_hdr = 4;
9875772Sas200622
9885772Sas200622 /* fixed part -- exactly one of these */
9895772Sas200622 n_fixed = ti->pdu_size_fixed_part;
9905772Sas200622
9915772Sas200622 /* variable part -- exactly size_of of these */
9925772Sas200622 n_variable = 0; /* 0 for the moment */
9935772Sas200622
9945772Sas200622 /* sum them up to determine the PDU space required */
9955772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
9965772Sas200622
9975772Sas200622 /* similar sum to determine how much local memory is required */
9985772Sas200622 n_alloc = n_fixed + n_variable;
9995772Sas200622
10005772Sas200622 /* For the moment, grow enough for the fixed-size part */
10018334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
10025772Sas200622 if (!rc)
10035772Sas200622 return (rc); /* error already set */
10045772Sas200622
10058334SJose.Borrego@Sun.COM switch (nds->m_op) {
10065772Sas200622 case NDR_M_OP_MARSHALL:
10075772Sas200622 /*
10085772Sas200622 * We don't know the size yet. We have to wait for
10095772Sas200622 * it. Proceed with the fixed-size part, and await
10108334SJose.Borrego@Sun.COM * the call to ndr_size_is().
10115772Sas200622 */
10125772Sas200622 size_is = 0;
10138334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
10145772Sas200622 if (!rc)
10155772Sas200622 return (0); /* error already set */
10165772Sas200622
10175772Sas200622 valp = outer_ref->datum;
1018*11633SJoyce.McIntosh@Sun.COM if (!valp) {
1019*11633SJoyce.McIntosh@Sun.COM NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
1020*11633SJoyce.McIntosh@Sun.COM return (0);
1021*11633SJoyce.McIntosh@Sun.COM }
102211447Samw@Sun.COM if (outer_ref->backptr)
10235772Sas200622 assert(valp == *outer_ref->backptr);
10245772Sas200622 break;
10255772Sas200622
10265772Sas200622 case NDR_M_OP_UNMARSHALL:
10275772Sas200622 /*
10285772Sas200622 * We know the size of the variable part because
10295772Sas200622 * of the CONFORMANT header. We will verify
10305772Sas200622 * the header against the [size_is(X)] advice
10318334SJose.Borrego@Sun.COM * later when ndr_size_is() is called.
10325772Sas200622 */
10338334SJose.Borrego@Sun.COM rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
10345772Sas200622 if (!rc)
10355772Sas200622 return (0); /* error already set */
10365772Sas200622
10375772Sas200622 /* recalculate metrics */
10385772Sas200622 n_variable = size_is * ti->pdu_size_variable_part;
10395772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
10405772Sas200622 n_alloc = n_fixed + n_variable;
10415772Sas200622
10428334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
10435772Sas200622 if (!rc)
10445772Sas200622 return (rc); /* error already set */
10455772Sas200622
10465772Sas200622 outer_ref->size_is = size_is; /* verified later */
10475772Sas200622
10488334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref);
10495772Sas200622 if (!valp) {
10505772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
10515772Sas200622 return (0);
10525772Sas200622 }
10535772Sas200622 if (outer_ref->backptr)
10545772Sas200622 *outer_ref->backptr = valp;
10555772Sas200622 outer_ref->datum = valp;
10565772Sas200622 break;
10575772Sas200622
10585772Sas200622 default:
10595772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
10605772Sas200622 return (0);
10615772Sas200622 }
10625772Sas200622
10636771Sjb150015 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
10646771Sjb150015 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
10656771Sjb150015 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */
10666771Sjb150015
10675772Sas200622 bzero(&myref, sizeof (myref));
10688334SJose.Borrego@Sun.COM myref.stream = nds;
10695772Sas200622 myref.enclosing = outer_ref;
10705772Sas200622 myref.ti = outer_ref->ti;
10715772Sas200622 myref.datum = outer_ref->datum;
10725772Sas200622 myref.name = "CONFORMANT-CONSTRUCT";
10735772Sas200622 myref.outer_flags = NDR_F_NONE;
10745772Sas200622 myref.inner_flags = NDR_F_NONE;
10755772Sas200622 myref.size_is = outer_ref->size_is;
10765772Sas200622
10775772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4;
10785772Sas200622
10798334SJose.Borrego@Sun.COM rc = ndr_inner(&myref);
10805772Sas200622 if (!rc)
10815772Sas200622 return (rc); /* error already set */
10825772Sas200622
10838334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
10845772Sas200622
10855772Sas200622 if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
10865772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
10875772Sas200622 return (0);
10885772Sas200622 }
10895772Sas200622
10905772Sas200622 return (1);
10915772Sas200622 }
10925772Sas200622
10935772Sas200622 int
ndr_size_is(ndr_ref_t * ref)10948334SJose.Borrego@Sun.COM ndr_size_is(ndr_ref_t *ref)
10955772Sas200622 {
10968334SJose.Borrego@Sun.COM ndr_stream_t *nds = ref->stream;
10978334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref = nds->outer_current;
10988334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
10995772Sas200622 unsigned long size_is;
11005772Sas200622 int rc;
11015772Sas200622 unsigned n_hdr;
11025772Sas200622 unsigned n_fixed;
11035772Sas200622 unsigned n_variable;
11045772Sas200622 unsigned n_pdu_total;
11055772Sas200622
11065772Sas200622 assert(ref->inner_flags & NDR_F_SIZE_IS);
11075772Sas200622 size_is = ref->size_is;
11085772Sas200622
11095772Sas200622 if (outer_ref->type_flags != NDR_F_SIZE_IS) {
11105772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
11115772Sas200622 return (0);
11125772Sas200622 }
11135772Sas200622
11145772Sas200622 if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
11155772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
11165772Sas200622 return (0);
11175772Sas200622 }
11185772Sas200622
11198334SJose.Borrego@Sun.COM /* repeat metrics, see ndr_conformant_construct() above */
11205772Sas200622 n_hdr = 4;
11215772Sas200622 n_fixed = ti->pdu_size_fixed_part;
11225772Sas200622 n_variable = size_is * ti->pdu_size_variable_part;
11235772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
11245772Sas200622
11258334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
11265772Sas200622 if (!rc)
11275772Sas200622 return (rc); /* error already set */
11285772Sas200622
11298334SJose.Borrego@Sun.COM switch (nds->m_op) {
11305772Sas200622 case NDR_M_OP_MARSHALL:
11315772Sas200622 /*
11325772Sas200622 * We have to set the sizing header and extend
11335772Sas200622 * the size of the PDU (already done).
11345772Sas200622 */
11358334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
11365772Sas200622 if (!rc)
11375772Sas200622 return (0); /* error already set */
11385772Sas200622 break;
11395772Sas200622
11405772Sas200622 case NDR_M_OP_UNMARSHALL:
11415772Sas200622 /*
11428334SJose.Borrego@Sun.COM * Allocation done during ndr_conformant_construct().
11435772Sas200622 * All we are doing here is verifying that the
11445772Sas200622 * intended size (ref->size_is) matches the sizing header.
11455772Sas200622 */
11465772Sas200622 if (size_is != outer_ref->size_is) {
11475772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
11485772Sas200622 return (0);
11495772Sas200622 }
11505772Sas200622 break;
11515772Sas200622
11525772Sas200622 default:
11535772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
11545772Sas200622 return (0);
11555772Sas200622 }
11565772Sas200622
11575772Sas200622 outer_ref->inner_flags |= NDR_F_SIZE_IS;
11585772Sas200622 outer_ref->size_is = ref->size_is;
11595772Sas200622 return (1);
11605772Sas200622 }
11615772Sas200622
11625772Sas200622 int
ndr_outer_string(ndr_ref_t * outer_ref)11638334SJose.Borrego@Sun.COM ndr_outer_string(ndr_ref_t *outer_ref)
11645772Sas200622 {
11658334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
11668334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti;
11678334SJose.Borrego@Sun.COM ndr_ref_t myref;
11685772Sas200622 char *valp = NULL;
11695772Sas200622 unsigned is_varlen = ti->pdu_size_variable_part;
11705772Sas200622 int is_union = NDR_IS_UNION(ti);
11715772Sas200622 int is_string = NDR_IS_STRING(ti);
11725772Sas200622 int rc;
11735772Sas200622 unsigned n_zeroes;
11745772Sas200622 unsigned ix;
11755772Sas200622 unsigned long size_is;
11765772Sas200622 unsigned long first_is;
11775772Sas200622 unsigned long length_is;
11785772Sas200622 unsigned n_hdr;
11795772Sas200622 unsigned n_fixed;
11805772Sas200622 unsigned n_variable;
11815772Sas200622 unsigned n_alloc;
11825772Sas200622 unsigned n_pdu_total;
11835772Sas200622 int params;
11845772Sas200622
11855772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
11865772Sas200622
11875772Sas200622 assert(is_varlen && is_string && !is_union);
11885772Sas200622 assert(params == NDR_F_NONE);
11895772Sas200622
11905772Sas200622 /* string header for this: size_is first_is length_is */
11915772Sas200622 n_hdr = 12;
11925772Sas200622
11935772Sas200622 /* fixed part -- exactly none of these */
11945772Sas200622 n_fixed = 0;
11955772Sas200622
11968334SJose.Borrego@Sun.COM if (!ndr_outer_grow(outer_ref, n_hdr))
11975772Sas200622 return (0); /* error already set */
11985772Sas200622
11998334SJose.Borrego@Sun.COM switch (nds->m_op) {
12005772Sas200622 case NDR_M_OP_MARSHALL:
12015772Sas200622 valp = outer_ref->datum;
1202*11633SJoyce.McIntosh@Sun.COM if (!valp) {
1203*11633SJoyce.McIntosh@Sun.COM NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
1204*11633SJoyce.McIntosh@Sun.COM return (0);
1205*11633SJoyce.McIntosh@Sun.COM }
12065772Sas200622
12075772Sas200622 if (outer_ref->backptr)
12085772Sas200622 assert(valp == *outer_ref->backptr);
12095772Sas200622
12105772Sas200622 if (ti == &ndt_s_wchar) {
12115772Sas200622 /*
121210717Samw@Sun.COM * size_is is the number of characters in the
121310717Samw@Sun.COM * (multibyte) string, including the null.
12145772Sas200622 */
121511337SWilliam.Krier@Sun.COM size_is = smb_wcequiv_strlen(valp) /
121611337SWilliam.Krier@Sun.COM sizeof (smb_wchar_t);
121711337SWilliam.Krier@Sun.COM
121811337SWilliam.Krier@Sun.COM if (!(nds->flags & NDS_F_NONULL))
121911337SWilliam.Krier@Sun.COM ++size_is;
12205772Sas200622
12215772Sas200622 if (size_is > NDR_STRING_MAX) {
12225772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
12235772Sas200622 return (0);
12245772Sas200622 }
12255772Sas200622 } else {
12265772Sas200622 valp = outer_ref->datum;
12275772Sas200622 n_zeroes = 0;
122811447Samw@Sun.COM for (ix = 0; ix < NDR_STRING_MAX; ix++) {
12295772Sas200622 if (valp[ix] == 0) {
12305772Sas200622 n_zeroes++;
12315772Sas200622 if (n_zeroes >= is_varlen &&
12325772Sas200622 ix % is_varlen == 0) {
12335772Sas200622 break;
12345772Sas200622 }
12355772Sas200622 } else {
12365772Sas200622 n_zeroes = 0;
12375772Sas200622 }
12385772Sas200622 }
123911447Samw@Sun.COM if (ix >= NDR_STRING_MAX) {
12405772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
12415772Sas200622 return (0);
12425772Sas200622 }
12435772Sas200622 size_is = ix+1;
12445772Sas200622 }
12455772Sas200622
12465772Sas200622 first_is = 0;
12475772Sas200622
12488334SJose.Borrego@Sun.COM if (nds->flags & NDS_F_NOTERM)
12495772Sas200622 length_is = size_is - 1;
12505772Sas200622 else
12515772Sas200622 length_is = size_is;
12525772Sas200622
12538334SJose.Borrego@Sun.COM if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
12548334SJose.Borrego@Sun.COM !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
12558334SJose.Borrego@Sun.COM !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
12565772Sas200622 return (0); /* error already set */
12575772Sas200622 break;
12585772Sas200622
12595772Sas200622 case NDR_M_OP_UNMARSHALL:
12608334SJose.Borrego@Sun.COM if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
12618334SJose.Borrego@Sun.COM !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
12628334SJose.Borrego@Sun.COM !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
12635772Sas200622 return (0); /* error already set */
12645772Sas200622
12655772Sas200622 /*
12665772Sas200622 * In addition to the first_is check, we used to check that
12675772Sas200622 * size_is or size_is-1 was equal to length_is but Windows95
12685772Sas200622 * doesn't conform to this "rule" (see variable part below).
12695772Sas200622 * The srvmgr tool for Windows95 sent the following values
12705772Sas200622 * for a path string:
12715772Sas200622 *
12725772Sas200622 * size_is = 261 (0x105)
12735772Sas200622 * first_is = 0
12745772Sas200622 * length_is = 53 (0x35)
12755772Sas200622 *
12765772Sas200622 * The length_is was correct (for the given path) but the
12775772Sas200622 * size_is was the maximum path length rather than being
12785772Sas200622 * related to length_is.
12795772Sas200622 */
12805772Sas200622 if (first_is != 0) {
12815772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
12825772Sas200622 return (0);
12835772Sas200622 }
12845772Sas200622
12855772Sas200622 if (ti == &ndt_s_wchar) {
12865772Sas200622 /*
12875772Sas200622 * Decoding Unicode to UTF-8; we need to allow
12885772Sas200622 * for the maximum possible char size. It would
12895772Sas200622 * be nice to use mbequiv_strlen but the string
12905772Sas200622 * may not be null terminated.
12915772Sas200622 */
12925772Sas200622 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
12935772Sas200622 } else {
12945772Sas200622 n_alloc = (size_is + 1) * is_varlen;
12955772Sas200622 }
12965772Sas200622
12978334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref);
12985772Sas200622 if (!valp) {
12995772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
13005772Sas200622 return (0);
13015772Sas200622 }
13025772Sas200622
13035772Sas200622 bzero(valp, (size_is+1) * is_varlen);
13045772Sas200622
13055772Sas200622 if (outer_ref->backptr)
13065772Sas200622 *outer_ref->backptr = valp;
13075772Sas200622 outer_ref->datum = valp;
13085772Sas200622 break;
13095772Sas200622
13105772Sas200622 default:
13115772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
13125772Sas200622 return (0);
13135772Sas200622 }
13145772Sas200622
13155772Sas200622 /*
13165772Sas200622 * Variable part - exactly length_is of these.
13175772Sas200622 *
13185772Sas200622 * Usually, length_is is same as size_is and includes nul.
13195772Sas200622 * Some protocols use length_is = size_is-1, and length_is does
13205772Sas200622 * not include the nul (which is more consistent with DCE spec).
13215772Sas200622 * If the length_is is 0, there is no data following the
13225772Sas200622 * sizing header, regardless of size_is.
13235772Sas200622 */
13245772Sas200622 n_variable = length_is * is_varlen;
13255772Sas200622
13265772Sas200622 /* sum them up to determine the PDU space required */
13275772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable;
13285772Sas200622
13295772Sas200622 /* similar sum to determine how much local memory is required */
13305772Sas200622 n_alloc = n_fixed + n_variable;
13315772Sas200622
13328334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total);
13335772Sas200622 if (!rc)
13345772Sas200622 return (rc); /* error already set */
13355772Sas200622
13365772Sas200622 if (length_is > 0) {
13375772Sas200622 bzero(&myref, sizeof (myref));
13388334SJose.Borrego@Sun.COM myref.stream = nds;
13395772Sas200622 myref.enclosing = outer_ref;
13405772Sas200622 myref.ti = outer_ref->ti;
13415772Sas200622 myref.datum = outer_ref->datum;
13425772Sas200622 myref.name = "OUTER-STRING";
13435772Sas200622 myref.outer_flags = NDR_F_IS_STRING;
13445772Sas200622 myref.inner_flags = NDR_F_NONE;
13455772Sas200622
13465772Sas200622 /*
13478334SJose.Borrego@Sun.COM * Set up size_is and strlen_is for ndr_s_wchar.
13485772Sas200622 */
13495772Sas200622 myref.size_is = size_is;
13505772Sas200622 myref.strlen_is = length_is;
13515772Sas200622 }
13525772Sas200622
13535772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 12;
13545772Sas200622
13555772Sas200622 /*
13565772Sas200622 * Don't try to decode empty strings.
13575772Sas200622 */
13585772Sas200622 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
13598334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
13605772Sas200622 return (1);
13615772Sas200622 }
13625772Sas200622
13635772Sas200622 if ((size_is != 0) && (length_is != 0)) {
13648334SJose.Borrego@Sun.COM rc = ndr_inner(&myref);
13655772Sas200622 if (!rc)
13665772Sas200622 return (rc); /* error already set */
13675772Sas200622 }
13685772Sas200622
13698334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset;
13705772Sas200622 return (1);
13715772Sas200622 }
13725772Sas200622
13735772Sas200622 int
ndr_outer_peek_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)13748334SJose.Borrego@Sun.COM ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
13755772Sas200622 unsigned long *sizing_p)
13765772Sas200622 {
13778334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
13788334SJose.Borrego@Sun.COM unsigned long pdu_offset;
13798334SJose.Borrego@Sun.COM int rc;
13805772Sas200622
13815772Sas200622 pdu_offset = outer_ref->pdu_offset + offset;
13825772Sas200622
13838334SJose.Borrego@Sun.COM if (pdu_offset < nds->outer_current->pdu_offset ||
13848334SJose.Borrego@Sun.COM pdu_offset > nds->outer_current->pdu_end_offset ||
13858334SJose.Borrego@Sun.COM pdu_offset+4 > nds->outer_current->pdu_end_offset) {
13865772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
13875772Sas200622 return (0);
13885772Sas200622 }
13895772Sas200622
13908334SJose.Borrego@Sun.COM switch (nds->m_op) {
13915772Sas200622 case NDR_M_OP_MARSHALL:
13925772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
13935772Sas200622 return (0);
13945772Sas200622
13955772Sas200622 case NDR_M_OP_UNMARSHALL:
13968334SJose.Borrego@Sun.COM rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
13978334SJose.Borrego@Sun.COM nds->swap, outer_ref);
13985772Sas200622 break;
13995772Sas200622
14005772Sas200622 default:
14015772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14025772Sas200622 return (0);
14035772Sas200622 }
14045772Sas200622
14055772Sas200622 return (rc);
14065772Sas200622 }
14075772Sas200622
14085772Sas200622 int
ndr_outer_poke_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)14098334SJose.Borrego@Sun.COM ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
14105772Sas200622 unsigned long *sizing_p)
14115772Sas200622 {
14128334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
14138334SJose.Borrego@Sun.COM unsigned long pdu_offset;
14148334SJose.Borrego@Sun.COM int rc;
14155772Sas200622
14165772Sas200622 pdu_offset = outer_ref->pdu_offset + offset;
14175772Sas200622
14188334SJose.Borrego@Sun.COM if (pdu_offset < nds->outer_current->pdu_offset ||
14198334SJose.Borrego@Sun.COM pdu_offset > nds->outer_current->pdu_end_offset ||
14208334SJose.Borrego@Sun.COM pdu_offset+4 > nds->outer_current->pdu_end_offset) {
14215772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
14225772Sas200622 return (0);
14235772Sas200622 }
14245772Sas200622
14258334SJose.Borrego@Sun.COM switch (nds->m_op) {
14265772Sas200622 case NDR_M_OP_MARSHALL:
14278334SJose.Borrego@Sun.COM rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
14288334SJose.Borrego@Sun.COM nds->swap, outer_ref);
14295772Sas200622 break;
14305772Sas200622
14315772Sas200622 case NDR_M_OP_UNMARSHALL:
14325772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
14335772Sas200622 return (0);
14345772Sas200622
14355772Sas200622 default:
14365772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14375772Sas200622 return (0);
14385772Sas200622 }
14395772Sas200622
14405772Sas200622 return (rc);
14415772Sas200622 }
14425772Sas200622
14435772Sas200622 /*
14445772Sas200622 * All OUTER constructs begin on a mod4 (dword) boundary - except
14455772Sas200622 * for the ones that don't: some MSRPC calls appear to use word or
14465772Sas200622 * packed alignment. Strings appear to be dword aligned.
14475772Sas200622 */
14485772Sas200622 int
ndr_outer_align(ndr_ref_t * outer_ref)14498334SJose.Borrego@Sun.COM ndr_outer_align(ndr_ref_t *outer_ref)
14505772Sas200622 {
14518334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
14528334SJose.Borrego@Sun.COM int rc;
14538334SJose.Borrego@Sun.COM unsigned n_pad;
14548334SJose.Borrego@Sun.COM unsigned align;
14555772Sas200622
14565772Sas200622 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
14575772Sas200622 align = outer_ref->ti->alignment;
14588334SJose.Borrego@Sun.COM n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
14595772Sas200622 } else {
14608334SJose.Borrego@Sun.COM n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
14615772Sas200622 }
14625772Sas200622
14635772Sas200622 if (n_pad == 0)
14645772Sas200622 return (1); /* already aligned, often the case */
14655772Sas200622
14668334SJose.Borrego@Sun.COM if (!ndr_outer_grow(outer_ref, n_pad))
14675772Sas200622 return (0); /* error already set */
14685772Sas200622
14698334SJose.Borrego@Sun.COM switch (nds->m_op) {
14705772Sas200622 case NDR_M_OP_MARSHALL:
14718334SJose.Borrego@Sun.COM rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
14725772Sas200622 if (!rc) {
14735772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
14745772Sas200622 return (0);
14755772Sas200622 }
14765772Sas200622 break;
14775772Sas200622
14785772Sas200622 case NDR_M_OP_UNMARSHALL:
14795772Sas200622 break;
14805772Sas200622
14815772Sas200622 default:
14825772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
14835772Sas200622 return (0);
14845772Sas200622 }
14855772Sas200622
14868334SJose.Borrego@Sun.COM nds->pdu_scan_offset += n_pad;
14875772Sas200622 return (1);
14885772Sas200622 }
14895772Sas200622
14905772Sas200622 int
ndr_outer_grow(ndr_ref_t * outer_ref,unsigned n_total)14918334SJose.Borrego@Sun.COM ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
14925772Sas200622 {
14938334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream;
14948334SJose.Borrego@Sun.COM unsigned long pdu_want_size;
14958334SJose.Borrego@Sun.COM int rc, is_ok = 0;
14965772Sas200622
14978334SJose.Borrego@Sun.COM pdu_want_size = nds->pdu_scan_offset + n_total;
14985772Sas200622
14998334SJose.Borrego@Sun.COM if (pdu_want_size <= nds->pdu_max_size) {
15005772Sas200622 is_ok = 1;
15015772Sas200622 }
15025772Sas200622
15038334SJose.Borrego@Sun.COM switch (nds->m_op) {
15045772Sas200622 case NDR_M_OP_MARSHALL:
15055772Sas200622 if (is_ok)
15065772Sas200622 break;
15078334SJose.Borrego@Sun.COM rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
15085772Sas200622 if (!rc) {
15095772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
15105772Sas200622 return (0);
15115772Sas200622 }
15125772Sas200622 break;
15135772Sas200622
15145772Sas200622 case NDR_M_OP_UNMARSHALL:
15155772Sas200622 if (is_ok)
15165772Sas200622 break;
15175772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
15185772Sas200622 return (0);
15195772Sas200622
15205772Sas200622 default:
15215772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
15225772Sas200622 return (0);
15235772Sas200622 }
15245772Sas200622
15258334SJose.Borrego@Sun.COM if (nds->pdu_size < pdu_want_size)
15268334SJose.Borrego@Sun.COM nds->pdu_size = pdu_want_size;
15275772Sas200622
15285772Sas200622 outer_ref->pdu_end_offset = pdu_want_size;
15295772Sas200622 return (1);
15305772Sas200622 }
15315772Sas200622
15325772Sas200622 /*
15335772Sas200622 * INNER ELEMENTS
15345772Sas200622 *
15355772Sas200622 * The local datum (arg_ref->datum) already exists, there is no need to
15365772Sas200622 * malloc() it. The datum should point at a member of a structure.
15375772Sas200622 *
15388334SJose.Borrego@Sun.COM * For the most part, ndr_inner() and its helpers are just a sanity
15395772Sas200622 * check. The underlying ti->ndr_func() could be called immediately
15405772Sas200622 * for non-pointer elements. For the sake of robustness, we detect
15415772Sas200622 * run-time errors here. Most of the situations this protects against
15425772Sas200622 * have already been checked by the IDL compiler. This is also a
15435772Sas200622 * common point for processing of all data, and so is a convenient
15445772Sas200622 * place to work from for debugging.
15455772Sas200622 */
15465772Sas200622 int
ndr_inner(ndr_ref_t * arg_ref)15478334SJose.Borrego@Sun.COM ndr_inner(ndr_ref_t *arg_ref)
15485772Sas200622 {
15498334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = arg_ref->ti;
15505772Sas200622 int is_varlen = ti->pdu_size_variable_part;
15515772Sas200622 int is_union = NDR_IS_UNION(ti);
15525772Sas200622 int error = NDR_ERR_INNER_PARAMS_BAD;
15535772Sas200622 int params;
15545772Sas200622
15555772Sas200622 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
15565772Sas200622
15575772Sas200622 switch (params) {
15585772Sas200622 case NDR_F_NONE:
15595772Sas200622 if (is_union) {
15605772Sas200622 error = NDR_ERR_SWITCH_VALUE_MISSING;
15615772Sas200622 break;
15625772Sas200622 }
15635772Sas200622 return (*ti->ndr_func)(arg_ref);
15645772Sas200622 break;
15655772Sas200622
15665772Sas200622 case NDR_F_SIZE_IS:
15675772Sas200622 case NDR_F_DIMENSION_IS:
15685772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */
15695772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
15705772Sas200622 if (is_varlen) {
15715772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
15725772Sas200622 break;
15735772Sas200622 }
15745772Sas200622 if (is_union) {
15755772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15765772Sas200622 break;
15775772Sas200622 }
15785772Sas200622 if (params & NDR_F_IS_POINTER)
15798334SJose.Borrego@Sun.COM return (ndr_inner_pointer(arg_ref));
15805772Sas200622 else if (params & NDR_F_IS_REFERENCE)
15818334SJose.Borrego@Sun.COM return (ndr_inner_reference(arg_ref));
15825772Sas200622 else
15838334SJose.Borrego@Sun.COM return (ndr_inner_array(arg_ref));
15845772Sas200622 break;
15855772Sas200622
15865772Sas200622 case NDR_F_IS_POINTER: /* type is pointer to one something */
15875772Sas200622 if (is_union) {
15885772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15895772Sas200622 break;
15905772Sas200622 }
15918334SJose.Borrego@Sun.COM return (ndr_inner_pointer(arg_ref));
15925772Sas200622 break;
15935772Sas200622
15945772Sas200622 case NDR_F_IS_REFERENCE: /* type is pointer to one something */
15955772Sas200622 if (is_union) {
15965772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
15975772Sas200622 break;
15985772Sas200622 }
15998334SJose.Borrego@Sun.COM return (ndr_inner_reference(arg_ref));
16005772Sas200622 break;
16015772Sas200622
16025772Sas200622 case NDR_F_SWITCH_IS:
16035772Sas200622 if (!is_union) {
16045772Sas200622 error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
16055772Sas200622 break;
16065772Sas200622 }
16075772Sas200622 return (*ti->ndr_func)(arg_ref);
16085772Sas200622 break;
16095772Sas200622
16105772Sas200622 default:
16115772Sas200622 error = NDR_ERR_INNER_PARAMS_BAD;
16125772Sas200622 break;
16135772Sas200622 }
16145772Sas200622
16155772Sas200622 /*
16165772Sas200622 * If we get here, something is wrong. Most likely,
16175772Sas200622 * the params flags do not match
16185772Sas200622 */
16195772Sas200622 NDR_SET_ERROR(arg_ref, error);
16205772Sas200622 return (0);
16215772Sas200622 }
16225772Sas200622
16235772Sas200622 int
ndr_inner_pointer(ndr_ref_t * arg_ref)16248334SJose.Borrego@Sun.COM ndr_inner_pointer(ndr_ref_t *arg_ref)
16255772Sas200622 {
16268334SJose.Borrego@Sun.COM ndr_stream_t *nds = arg_ref->stream;
16275772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/
16288334SJose.Borrego@Sun.COM char **valpp = (char **)arg_ref->datum;
16298334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref;
16305772Sas200622
16318334SJose.Borrego@Sun.COM if (!ndr__ulong(arg_ref))
16325772Sas200622 return (0); /* error */
16335772Sas200622 if (!*valpp)
16345772Sas200622 return (1); /* NULL pointer */
16355772Sas200622
16368334SJose.Borrego@Sun.COM outer_ref = ndr_enter_outer_queue(arg_ref);
16375772Sas200622 if (!outer_ref)
16385772Sas200622 return (0); /* error already set */
16395772Sas200622
164011447Samw@Sun.COM /*
164111447Samw@Sun.COM * Move advice in inner_flags to outer_flags.
164211447Samw@Sun.COM * Retain pointer flag for conformant arrays.
164311447Samw@Sun.COM */
16445772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
164511447Samw@Sun.COM if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
164611447Samw@Sun.COM outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
164711447Samw@Sun.COM #ifdef NDR_INNER_PTR_NOT_YET
16485772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR;
16495772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
16505772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
16515772Sas200622 }
165211447Samw@Sun.COM #endif /* NDR_INNER_PTR_NOT_YET */
16535772Sas200622
16545772Sas200622 outer_ref->backptr = valpp;
16555772Sas200622
16568334SJose.Borrego@Sun.COM switch (nds->m_op) {
16575772Sas200622 case NDR_M_OP_MARSHALL:
16585772Sas200622 outer_ref->datum = *valpp;
16595772Sas200622 break;
16605772Sas200622
16615772Sas200622 case NDR_M_OP_UNMARSHALL:
16625772Sas200622 /*
16635772Sas200622 * This is probably wrong if the application allocated
16645772Sas200622 * memory in advance. Indicate no value for now.
16655772Sas200622 * ONC RPC handles this case.
16665772Sas200622 */
16675772Sas200622 *valpp = 0;
16685772Sas200622 outer_ref->datum = 0;
16695772Sas200622 break;
16705772Sas200622 }
16715772Sas200622
16725772Sas200622 return (1); /* pointer dereference scheduled */
16735772Sas200622 }
16745772Sas200622
16755772Sas200622 int
ndr_inner_reference(ndr_ref_t * arg_ref)16768334SJose.Borrego@Sun.COM ndr_inner_reference(ndr_ref_t *arg_ref)
16775772Sas200622 {
16788334SJose.Borrego@Sun.COM ndr_stream_t *nds = arg_ref->stream;
16795772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/
16808334SJose.Borrego@Sun.COM char **valpp = (char **)arg_ref->datum;
16818334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref;
16825772Sas200622
16838334SJose.Borrego@Sun.COM outer_ref = ndr_enter_outer_queue(arg_ref);
16845772Sas200622 if (!outer_ref)
16855772Sas200622 return (0); /* error already set */
16865772Sas200622
168711447Samw@Sun.COM /*
168811447Samw@Sun.COM * Move advice in inner_flags to outer_flags.
168911447Samw@Sun.COM * Retain reference flag for conformant arrays.
169011447Samw@Sun.COM */
16915772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
169211447Samw@Sun.COM if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
169311447Samw@Sun.COM outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
16945772Sas200622 #ifdef NDR_INNER_REF_NOT_YET
16955772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR;
16965772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
16975772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
16985772Sas200622 }
16995772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */
17005772Sas200622
17015772Sas200622 outer_ref->backptr = valpp;
17025772Sas200622
17038334SJose.Borrego@Sun.COM switch (nds->m_op) {
17045772Sas200622 case NDR_M_OP_MARSHALL:
17055772Sas200622 outer_ref->datum = *valpp;
17065772Sas200622 break;
17075772Sas200622
17085772Sas200622 case NDR_M_OP_UNMARSHALL:
17095772Sas200622 /*
17105772Sas200622 * This is probably wrong if the application allocated
17115772Sas200622 * memory in advance. Indicate no value for now.
17125772Sas200622 * ONC RPC handles this case.
17135772Sas200622 */
17145772Sas200622 *valpp = 0;
17155772Sas200622 outer_ref->datum = 0;
17165772Sas200622 break;
17175772Sas200622 }
17185772Sas200622
17195772Sas200622 return (1); /* pointer dereference scheduled */
17205772Sas200622 }
17215772Sas200622
17225772Sas200622 int
ndr_inner_array(ndr_ref_t * encl_ref)17238334SJose.Borrego@Sun.COM ndr_inner_array(ndr_ref_t *encl_ref)
17245772Sas200622 {
17258334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = encl_ref->ti;
17268334SJose.Borrego@Sun.COM ndr_ref_t myref;
17275772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset;
17285772Sas200622 unsigned long n_elem;
17295772Sas200622 unsigned long i;
17305772Sas200622 char name[30];
17315772Sas200622
17325772Sas200622 if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
17335772Sas200622 /* now is the time to check/set size */
17348334SJose.Borrego@Sun.COM if (!ndr_size_is(encl_ref))
17355772Sas200622 return (0); /* error already set */
17365772Sas200622 n_elem = encl_ref->size_is;
17375772Sas200622 } else {
17385772Sas200622 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
17395772Sas200622 n_elem = encl_ref->dimension_is;
17405772Sas200622 }
17415772Sas200622
17425772Sas200622 bzero(&myref, sizeof (myref));
17435772Sas200622 myref.enclosing = encl_ref;
17445772Sas200622 myref.stream = encl_ref->stream;
17455772Sas200622 myref.packed_alignment = 0;
17465772Sas200622 myref.ti = ti;
17475772Sas200622 myref.inner_flags = NDR_F_NONE;
17485772Sas200622
17495772Sas200622 for (i = 0; i < n_elem; i++) {
17505772Sas200622 (void) sprintf(name, "[%lu]", i);
17515772Sas200622 myref.name = name;
17525772Sas200622 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
17535772Sas200622 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
17545772Sas200622
17558334SJose.Borrego@Sun.COM if (!ndr_inner(&myref))
17565772Sas200622 return (0);
17575772Sas200622 }
17585772Sas200622
17595772Sas200622 return (1);
17605772Sas200622 }
17615772Sas200622
17625772Sas200622
17635772Sas200622 /*
17645772Sas200622 * BASIC TYPES
17655772Sas200622 */
17665772Sas200622 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
17678334SJose.Borrego@Sun.COM extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
17688334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_##TYPE = { \
17695772Sas200622 1, /* NDR version */ \
17705772Sas200622 (SIZE)-1, /* alignment */ \
17715772Sas200622 NDR_F_NONE, /* flags */ \
17728334SJose.Borrego@Sun.COM ndr_##TYPE, /* ndr_func */ \
17735772Sas200622 SIZE, /* pdu_size_fixed_part */ \
17745772Sas200622 0, /* pdu_size_variable_part */ \
17755772Sas200622 SIZE, /* c_size_fixed_part */ \
17765772Sas200622 0, /* c_size_variable_part */ \
17775772Sas200622 }; \
17788334SJose.Borrego@Sun.COM int ndr_##TYPE(struct ndr_reference *ref) { \
17798334SJose.Borrego@Sun.COM return (ndr_basic_integer(ref, SIZE)); \
17805772Sas200622 }
17815772Sas200622
17825772Sas200622 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
17838334SJose.Borrego@Sun.COM extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
17848334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_s##TYPE = { \
17855772Sas200622 1, /* NDR version */ \
17865772Sas200622 (SIZE)-1, /* alignment */ \
17875772Sas200622 NDR_F_STRING, /* flags */ \
17888334SJose.Borrego@Sun.COM ndr_s##TYPE, /* ndr_func */ \
17895772Sas200622 0, /* pdu_size_fixed_part */ \
17905772Sas200622 SIZE, /* pdu_size_variable_part */ \
17915772Sas200622 0, /* c_size_fixed_part */ \
17925772Sas200622 SIZE, /* c_size_variable_part */ \
17935772Sas200622 }; \
17948334SJose.Borrego@Sun.COM int ndr_s##TYPE(struct ndr_reference *ref) { \
17958334SJose.Borrego@Sun.COM return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
17965772Sas200622 }
17975772Sas200622
17985772Sas200622 #define MAKE_BASIC_TYPE(TYPE, SIZE) \
17995772Sas200622 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
18005772Sas200622 MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
18015772Sas200622
18028334SJose.Borrego@Sun.COM int ndr_basic_integer(ndr_ref_t *, unsigned);
18038334SJose.Borrego@Sun.COM int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
18045772Sas200622
18055772Sas200622
18065772Sas200622 MAKE_BASIC_TYPE(_char, 1)
18075772Sas200622 MAKE_BASIC_TYPE(_uchar, 1)
18085772Sas200622 MAKE_BASIC_TYPE(_short, 2)
18095772Sas200622 MAKE_BASIC_TYPE(_ushort, 2)
18105772Sas200622 MAKE_BASIC_TYPE(_long, 4)
18115772Sas200622 MAKE_BASIC_TYPE(_ulong, 4)
18125772Sas200622
18135772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2)
18145772Sas200622
18155772Sas200622 int
ndr_basic_integer(ndr_ref_t * ref,unsigned size)18168334SJose.Borrego@Sun.COM ndr_basic_integer(ndr_ref_t *ref, unsigned size)
18175772Sas200622 {
18188334SJose.Borrego@Sun.COM ndr_stream_t *nds = ref->stream;
18198334SJose.Borrego@Sun.COM char *valp = (char *)ref->datum;
18208334SJose.Borrego@Sun.COM int rc;
18215772Sas200622
18228334SJose.Borrego@Sun.COM switch (nds->m_op) {
18235772Sas200622 case NDR_M_OP_MARSHALL:
18248334SJose.Borrego@Sun.COM rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
18258334SJose.Borrego@Sun.COM valp, nds->swap, ref);
18265772Sas200622 break;
18275772Sas200622
18285772Sas200622 case NDR_M_OP_UNMARSHALL:
18298334SJose.Borrego@Sun.COM rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
18308334SJose.Borrego@Sun.COM valp, nds->swap, ref);
18315772Sas200622 break;
18325772Sas200622
18335772Sas200622 default:
18345772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
18355772Sas200622 return (0);
18365772Sas200622 }
18375772Sas200622
18385772Sas200622 return (rc);
18395772Sas200622 }
18405772Sas200622
18415772Sas200622 int
ndr_string_basic_integer(ndr_ref_t * encl_ref,ndr_typeinfo_t * type_under)18428334SJose.Borrego@Sun.COM ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
18435772Sas200622 {
18445772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset;
18455772Sas200622 unsigned size = type_under->pdu_size_fixed_part;
18465772Sas200622 char *valp;
18478334SJose.Borrego@Sun.COM ndr_ref_t myref;
18485772Sas200622 unsigned long i;
18495772Sas200622 long sense = 0;
18505772Sas200622 char name[30];
18515772Sas200622
18525772Sas200622 assert(size != 0);
18535772Sas200622
18545772Sas200622 bzero(&myref, sizeof (myref));
18555772Sas200622 myref.enclosing = encl_ref;
18565772Sas200622 myref.stream = encl_ref->stream;
18575772Sas200622 myref.packed_alignment = 0;
18585772Sas200622 myref.ti = type_under;
18595772Sas200622 myref.inner_flags = NDR_F_NONE;
18605772Sas200622 myref.name = name;
18615772Sas200622
18625772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) {
18635772Sas200622 (void) sprintf(name, "[%lu]", i);
18645772Sas200622 myref.pdu_offset = pdu_offset + i * size;
18655772Sas200622 valp = encl_ref->datum + i * size;
18665772Sas200622 myref.datum = valp;
18675772Sas200622
18688334SJose.Borrego@Sun.COM if (!ndr_inner(&myref))
18695772Sas200622 return (0);
18705772Sas200622
18715772Sas200622 switch (size) {
18725772Sas200622 case 1: sense = *valp; break;
18735772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/
18745772Sas200622 case 2: sense = *(short *)valp; break;
18755772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/
18765772Sas200622 case 4: sense = *(long *)valp; break;
18775772Sas200622 }
18785772Sas200622
18795772Sas200622 if (!sense)
18805772Sas200622 break;
18815772Sas200622 }
18825772Sas200622
18835772Sas200622 return (1);
18845772Sas200622 }
18855772Sas200622
18865772Sas200622
18878334SJose.Borrego@Sun.COM extern int ndr_s_wchar(ndr_ref_t *encl_ref);
18888334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_s_wchar = {
18895772Sas200622 1, /* NDR version */
18905772Sas200622 2-1, /* alignment */
18915772Sas200622 NDR_F_STRING, /* flags */
18928334SJose.Borrego@Sun.COM ndr_s_wchar, /* ndr_func */
18935772Sas200622 0, /* pdu_size_fixed_part */
18945772Sas200622 2, /* pdu_size_variable_part */
18955772Sas200622 0, /* c_size_fixed_part */
18965772Sas200622 1, /* c_size_variable_part */
18975772Sas200622 };
18985772Sas200622
18995772Sas200622
19005772Sas200622 /*
19015772Sas200622 * Hand coded wchar function because all strings are transported
19025772Sas200622 * as wide characters. During NDR_M_OP_MARSHALL, we convert from
19035772Sas200622 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
19045772Sas200622 * convert from wide characters to multi-byte.
19055772Sas200622 *
19065772Sas200622 * It appeared that NT would sometimes leave a spurious character
19075772Sas200622 * in the data stream before the null wide_char, which would get
19085772Sas200622 * included in the string decode because we processed until the
19095772Sas200622 * null character. It now looks like NT does not always terminate
19105772Sas200622 * RPC Unicode strings and the terminating null is a side effect
19115772Sas200622 * of field alignment. So now we rely on the strlen_is (set up in
19128334SJose.Borrego@Sun.COM * ndr_outer_string) of the enclosing reference. This may or may
19135772Sas200622 * not include the null but it doesn't matter, the algorithm will
19145772Sas200622 * get it right.
19155772Sas200622 */
19165772Sas200622 int
ndr_s_wchar(ndr_ref_t * encl_ref)19178334SJose.Borrego@Sun.COM ndr_s_wchar(ndr_ref_t *encl_ref)
19185772Sas200622 {
19198334SJose.Borrego@Sun.COM ndr_stream_t *nds = encl_ref->stream;
19205772Sas200622 unsigned short wide_char;
19215772Sas200622 char *valp;
19228334SJose.Borrego@Sun.COM ndr_ref_t myref;
19235772Sas200622 unsigned long i;
19245772Sas200622 char name[30];
19255772Sas200622 int count;
19265772Sas200622 int char_count = 0;
19275772Sas200622
19288334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_UNMARSHALL) {
19295772Sas200622 /*
19305772Sas200622 * To avoid problems with zero length strings
19315772Sas200622 * we can just null terminate here and be done.
19325772Sas200622 */
19335772Sas200622 if (encl_ref->strlen_is == 0) {
19345772Sas200622 encl_ref->datum[0] = '\0';
19355772Sas200622 return (1);
19365772Sas200622 }
19375772Sas200622 }
19385772Sas200622
19395772Sas200622 bzero(&myref, sizeof (myref));
19405772Sas200622 myref.enclosing = encl_ref;
19415772Sas200622 myref.stream = encl_ref->stream;
19425772Sas200622 myref.packed_alignment = 0;
19435772Sas200622 myref.ti = &ndt__wchar;
19445772Sas200622 myref.inner_flags = NDR_F_NONE;
19455772Sas200622 myref.datum = (char *)&wide_char;
19465772Sas200622 myref.name = name;
19475772Sas200622 myref.pdu_offset = encl_ref->pdu_offset;
19485772Sas200622
19495772Sas200622 valp = encl_ref->datum;
19505772Sas200622 count = 0;
19515772Sas200622
19525772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) {
19535772Sas200622 (void) sprintf(name, "[%lu]", i);
19545772Sas200622
19558334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_MARSHALL) {
195610966SJordan.Brown@Sun.COM count = smb_mbtowc((smb_wchar_t *)&wide_char, valp,
19575772Sas200622 MTS_MB_CHAR_MAX);
19585772Sas200622 if (count < 0) {
19595772Sas200622 return (0);
19605772Sas200622 } else if (count == 0) {
19615772Sas200622 if (encl_ref->strlen_is != encl_ref->size_is)
19625772Sas200622 break;
19635772Sas200622
19645772Sas200622 /*
19655772Sas200622 * If the input char is 0, mbtowc
19665772Sas200622 * returns 0 without setting wide_char.
19675772Sas200622 * Set wide_char to 0 and a count of 1.
19685772Sas200622 */
19695772Sas200622 wide_char = *valp;
19705772Sas200622 count = 1;
19715772Sas200622 }
19725772Sas200622 }
19735772Sas200622
19748334SJose.Borrego@Sun.COM if (!ndr_inner(&myref))
19755772Sas200622 return (0);
19765772Sas200622
19778334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_UNMARSHALL) {
197810966SJordan.Brown@Sun.COM count = smb_wctomb(valp, wide_char);
19795772Sas200622
19805772Sas200622 if ((++char_count) == encl_ref->strlen_is) {
19815772Sas200622 valp += count;
19825772Sas200622 *valp = '\0';
19835772Sas200622 break;
19845772Sas200622 }
19855772Sas200622 }
19865772Sas200622
19875772Sas200622 if (!wide_char)
19885772Sas200622 break;
19895772Sas200622
19905772Sas200622 myref.pdu_offset += sizeof (wide_char);
19915772Sas200622 valp += count;
19925772Sas200622 }
19935772Sas200622
19945772Sas200622 return (1);
19955772Sas200622 }
19965772Sas200622
19975772Sas200622 /*
19985772Sas200622 * Converts a multibyte character string to a little-endian, wide-char
19995772Sas200622 * string. No more than nwchars wide characters are stored.
20005772Sas200622 * A terminating null wide character is appended if there is room.
20015772Sas200622 *
20025772Sas200622 * Returns the number of wide characters converted, not counting
20035772Sas200622 * any terminating null wide character. Returns -1 if an invalid
20045772Sas200622 * multibyte character is encountered.
20055772Sas200622 */
20065772Sas200622 size_t
ndr_mbstowcs(ndr_stream_t * nds,smb_wchar_t * wcs,const char * mbs,size_t nwchars)200710966SJordan.Brown@Sun.COM ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs,
20085772Sas200622 size_t nwchars)
20095772Sas200622 {
201010966SJordan.Brown@Sun.COM smb_wchar_t *start = wcs;
20115772Sas200622 int nbytes;
20125772Sas200622
20135772Sas200622 while (nwchars--) {
20148334SJose.Borrego@Sun.COM nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX);
20155772Sas200622 if (nbytes < 0) {
20165772Sas200622 *wcs = 0;
20175772Sas200622 return ((size_t)-1);
20185772Sas200622 }
20195772Sas200622
20205772Sas200622 if (*mbs == 0)
20215772Sas200622 break;
20225772Sas200622
20235772Sas200622 ++wcs;
20245772Sas200622 mbs += nbytes;
20255772Sas200622 }
20265772Sas200622
20275772Sas200622 return (wcs - start);
20285772Sas200622 }
20295772Sas200622
20305772Sas200622 /*
20315772Sas200622 * Converts a multibyte character to a little-endian, wide-char, which
20325772Sas200622 * is stored in wcharp. Up to nbytes bytes are examined.
20335772Sas200622 *
20345772Sas200622 * If mbchar is valid, returns the number of bytes processed in mbchar.
203510966SJordan.Brown@Sun.COM * If mbchar is invalid, returns -1. See also smb_mbtowc().
20365772Sas200622 */
20375772Sas200622 /*ARGSUSED*/
20385772Sas200622 int
ndr_mbtowc(ndr_stream_t * nds,smb_wchar_t * wcharp,const char * mbchar,size_t nbytes)203910966SJordan.Brown@Sun.COM ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar,
20408334SJose.Borrego@Sun.COM size_t nbytes)
20415772Sas200622 {
20425772Sas200622 int rc;
20435772Sas200622
204410966SJordan.Brown@Sun.COM if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0)
20455772Sas200622 return (rc);
20465772Sas200622
20475772Sas200622 #ifdef _BIG_ENDIAN
20488334SJose.Borrego@Sun.COM if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND))
20495772Sas200622 *wcharp = BSWAP_16(*wcharp);
20505772Sas200622 #endif
20515772Sas200622
20525772Sas200622 return (rc);
20535772Sas200622 }
2054