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 /* 2210717Samw@Sun.COM * Copyright 2009 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 425772Sas200622 #define NDR_STRING_MAX 256 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 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 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 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 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 * 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 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 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: 6265772Sas200622 if (is_varlen) { 6275772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 6285772Sas200622 break; 6295772Sas200622 } 6305772Sas200622 6315772Sas200622 if (params == NDR_F_SIZE_IS) 6328334SJose.Borrego@Sun.COM return (ndr_outer_conformant_array(outer_ref)); 6335772Sas200622 else 6348334SJose.Borrego@Sun.COM return (ndr_outer_fixed_array(outer_ref)); 6355772Sas200622 break; 6365772Sas200622 6375772Sas200622 default: 6385772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 6395772Sas200622 break; 6405772Sas200622 } 6415772Sas200622 6425772Sas200622 /* 6435772Sas200622 * If we get here, something is wrong. Most likely, 6445772Sas200622 * the params flags do not match. 6455772Sas200622 */ 6465772Sas200622 NDR_SET_ERROR(outer_ref, error); 6475772Sas200622 return (0); 6485772Sas200622 } 6495772Sas200622 6505772Sas200622 int 6518334SJose.Borrego@Sun.COM ndr_outer_fixed(ndr_ref_t *outer_ref) 6525772Sas200622 { 6538334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 6548334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 6558334SJose.Borrego@Sun.COM ndr_ref_t myref; 6565772Sas200622 char *valp = NULL; 6575772Sas200622 int is_varlen = ti->pdu_size_variable_part; 6585772Sas200622 int is_union = NDR_IS_UNION(ti); 6595772Sas200622 int is_string = NDR_IS_STRING(ti); 6605772Sas200622 int rc; 6615772Sas200622 unsigned n_hdr; 6625772Sas200622 unsigned n_fixed; 6635772Sas200622 unsigned n_variable; 6645772Sas200622 unsigned n_alloc; 6655772Sas200622 unsigned n_pdu_total; 6665772Sas200622 int params; 6675772Sas200622 6685772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 6695772Sas200622 6705772Sas200622 assert(!is_varlen && !is_string && !is_union); 6715772Sas200622 assert(params == NDR_F_NONE); 6725772Sas200622 6735772Sas200622 /* no header for this */ 6745772Sas200622 n_hdr = 0; 6755772Sas200622 6765772Sas200622 /* fixed part -- exactly one of these */ 6775772Sas200622 n_fixed = ti->pdu_size_fixed_part; 6785772Sas200622 assert(n_fixed > 0); 6795772Sas200622 6805772Sas200622 /* variable part -- exactly none of these */ 6815772Sas200622 n_variable = 0; 6825772Sas200622 6835772Sas200622 /* sum them up to determine the PDU space required */ 6845772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 6855772Sas200622 6865772Sas200622 /* similar sum to determine how much local memory is required */ 6875772Sas200622 n_alloc = n_fixed + n_variable; 6885772Sas200622 6898334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 6905772Sas200622 if (!rc) 6915772Sas200622 return (rc); /* error already set */ 6925772Sas200622 6938334SJose.Borrego@Sun.COM switch (nds->m_op) { 6945772Sas200622 case NDR_M_OP_MARSHALL: 6955772Sas200622 valp = outer_ref->datum; 6965772Sas200622 assert(valp); 6975772Sas200622 if (outer_ref->backptr) { 6985772Sas200622 assert(valp == *outer_ref->backptr); 6995772Sas200622 } 7005772Sas200622 break; 7015772Sas200622 7025772Sas200622 case NDR_M_OP_UNMARSHALL: 7038334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref); 7045772Sas200622 if (!valp) { 7055772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 7065772Sas200622 return (0); 7075772Sas200622 } 7085772Sas200622 if (outer_ref->backptr) 7095772Sas200622 *outer_ref->backptr = valp; 7105772Sas200622 outer_ref->datum = valp; 7115772Sas200622 break; 7125772Sas200622 7135772Sas200622 default: 7145772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 7155772Sas200622 return (0); 7165772Sas200622 } 7175772Sas200622 7185772Sas200622 bzero(&myref, sizeof (myref)); 7198334SJose.Borrego@Sun.COM myref.stream = nds; 7205772Sas200622 myref.enclosing = outer_ref; 7215772Sas200622 myref.ti = outer_ref->ti; 7225772Sas200622 myref.datum = outer_ref->datum; 7235772Sas200622 myref.name = "FIXED-VALUE"; 7245772Sas200622 myref.outer_flags = NDR_F_NONE; 7255772Sas200622 myref.inner_flags = NDR_F_NONE; 7265772Sas200622 7275772Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 7285772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 7295772Sas200622 7308334SJose.Borrego@Sun.COM rc = ndr_inner(&myref); 7315772Sas200622 if (!rc) 7325772Sas200622 return (rc); /* error already set */ 7335772Sas200622 7348334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 7355772Sas200622 return (1); 7365772Sas200622 } 7375772Sas200622 7385772Sas200622 int 7398334SJose.Borrego@Sun.COM ndr_outer_fixed_array(ndr_ref_t *outer_ref) 7405772Sas200622 { 7418334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 7428334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 7438334SJose.Borrego@Sun.COM ndr_ref_t myref; 7445772Sas200622 char *valp = NULL; 7455772Sas200622 int is_varlen = ti->pdu_size_variable_part; 7465772Sas200622 int is_union = NDR_IS_UNION(ti); 7475772Sas200622 int is_string = NDR_IS_STRING(ti); 7485772Sas200622 int rc; 7495772Sas200622 unsigned n_hdr; 7505772Sas200622 unsigned n_fixed; 7515772Sas200622 unsigned n_variable; 7525772Sas200622 unsigned n_alloc; 7535772Sas200622 unsigned n_pdu_total; 7545772Sas200622 int params; 7555772Sas200622 7565772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 7575772Sas200622 7585772Sas200622 assert(!is_varlen && !is_string && !is_union); 7595772Sas200622 assert(params == NDR_F_DIMENSION_IS); 7605772Sas200622 7615772Sas200622 /* no header for this */ 7625772Sas200622 n_hdr = 0; 7635772Sas200622 7645772Sas200622 /* fixed part -- exactly dimension_is of these */ 7655772Sas200622 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 7665772Sas200622 assert(n_fixed > 0); 7675772Sas200622 7685772Sas200622 /* variable part -- exactly none of these */ 7695772Sas200622 n_variable = 0; 7705772Sas200622 7715772Sas200622 /* sum them up to determine the PDU space required */ 7725772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 7735772Sas200622 7745772Sas200622 /* similar sum to determine how much local memory is required */ 7755772Sas200622 n_alloc = n_fixed + n_variable; 7765772Sas200622 7778334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 7785772Sas200622 if (!rc) 7795772Sas200622 return (rc); /* error already set */ 7805772Sas200622 7818334SJose.Borrego@Sun.COM switch (nds->m_op) { 7825772Sas200622 case NDR_M_OP_MARSHALL: 7835772Sas200622 valp = outer_ref->datum; 7845772Sas200622 assert(valp); 7855772Sas200622 if (outer_ref->backptr) { 7865772Sas200622 assert(valp == *outer_ref->backptr); 7875772Sas200622 } 7885772Sas200622 break; 7895772Sas200622 7905772Sas200622 case NDR_M_OP_UNMARSHALL: 7918334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref); 7925772Sas200622 if (!valp) { 7935772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 7945772Sas200622 return (0); 7955772Sas200622 } 7965772Sas200622 if (outer_ref->backptr) 7975772Sas200622 *outer_ref->backptr = valp; 7985772Sas200622 outer_ref->datum = valp; 7995772Sas200622 break; 8005772Sas200622 8015772Sas200622 default: 8025772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 8035772Sas200622 return (0); 8045772Sas200622 } 8055772Sas200622 8065772Sas200622 bzero(&myref, sizeof (myref)); 8078334SJose.Borrego@Sun.COM myref.stream = nds; 8085772Sas200622 myref.enclosing = outer_ref; 8095772Sas200622 myref.ti = outer_ref->ti; 8105772Sas200622 myref.datum = outer_ref->datum; 8115772Sas200622 myref.name = "FIXED-ARRAY"; 8125772Sas200622 myref.outer_flags = NDR_F_NONE; 8135772Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS; 8145772Sas200622 myref.dimension_is = outer_ref->dimension_is; 8155772Sas200622 8165772Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 8175772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 8185772Sas200622 8198334SJose.Borrego@Sun.COM rc = ndr_inner(&myref); 8205772Sas200622 if (!rc) 8215772Sas200622 return (rc); /* error already set */ 8225772Sas200622 8238334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 8245772Sas200622 return (1); 8255772Sas200622 } 8265772Sas200622 8275772Sas200622 int 8288334SJose.Borrego@Sun.COM ndr_outer_conformant_array(ndr_ref_t *outer_ref) 8295772Sas200622 { 8308334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 8318334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 8328334SJose.Borrego@Sun.COM ndr_ref_t myref; 8335772Sas200622 char *valp = NULL; 8345772Sas200622 int is_varlen = ti->pdu_size_variable_part; 8355772Sas200622 int is_union = NDR_IS_UNION(ti); 8365772Sas200622 int is_string = NDR_IS_STRING(ti); 8375772Sas200622 unsigned long size_is; 8385772Sas200622 int rc; 8395772Sas200622 unsigned n_hdr; 8405772Sas200622 unsigned n_fixed; 8415772Sas200622 unsigned n_variable; 8425772Sas200622 unsigned n_alloc; 8435772Sas200622 unsigned n_pdu_total; 8445772Sas200622 int params; 8455772Sas200622 8465772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 8475772Sas200622 8485772Sas200622 assert(!is_varlen && !is_string && !is_union); 8495772Sas200622 assert(params == NDR_F_SIZE_IS); 8505772Sas200622 8515772Sas200622 /* conformant header for this */ 8525772Sas200622 n_hdr = 4; 8535772Sas200622 8545772Sas200622 /* fixed part -- exactly none of these */ 8555772Sas200622 n_fixed = 0; 8565772Sas200622 8575772Sas200622 /* variable part -- exactly size_of of these */ 8585772Sas200622 /* notice that it is the **fixed** size of the ti */ 8595772Sas200622 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 8605772Sas200622 8615772Sas200622 /* sum them up to determine the PDU space required */ 8625772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 8635772Sas200622 8645772Sas200622 /* similar sum to determine how much local memory is required */ 8655772Sas200622 n_alloc = n_fixed + n_variable; 8665772Sas200622 8678334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 8685772Sas200622 if (!rc) 8695772Sas200622 return (rc); /* error already set */ 8705772Sas200622 8718334SJose.Borrego@Sun.COM switch (nds->m_op) { 8725772Sas200622 case NDR_M_OP_MARSHALL: 8735772Sas200622 size_is = outer_ref->size_is; 8748334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 8755772Sas200622 if (!rc) 8765772Sas200622 return (0); /* error already set */ 8775772Sas200622 8785772Sas200622 valp = outer_ref->datum; 8795772Sas200622 assert(valp); 8805772Sas200622 if (outer_ref->backptr) { 8815772Sas200622 assert(valp == *outer_ref->backptr); 8825772Sas200622 } 8835772Sas200622 break; 8845772Sas200622 8855772Sas200622 case NDR_M_OP_UNMARSHALL: 8868334SJose.Borrego@Sun.COM rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 8875772Sas200622 if (!rc) 8885772Sas200622 return (0); /* error already set */ 8895772Sas200622 8905772Sas200622 if (size_is != outer_ref->size_is) { 8915772Sas200622 NDR_SET_ERROR(outer_ref, 8925772Sas200622 NDR_ERR_SIZE_IS_MISMATCH_PDU); 8935772Sas200622 return (0); 8945772Sas200622 } 8955772Sas200622 8966771Sjb150015 if (size_is > 0) { 8978334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref); 8986771Sjb150015 if (!valp) { 8996771Sjb150015 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 9006771Sjb150015 return (0); 9016771Sjb150015 } 9025772Sas200622 } 9036771Sjb150015 9045772Sas200622 if (outer_ref->backptr) 9055772Sas200622 *outer_ref->backptr = valp; 9065772Sas200622 outer_ref->datum = valp; 9075772Sas200622 break; 9085772Sas200622 9095772Sas200622 default: 9105772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 9115772Sas200622 return (0); 9125772Sas200622 } 9135772Sas200622 9145772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 9155772Sas200622 outer_ref->type_flags = NDR_F_NONE; 9165772Sas200622 outer_ref->inner_flags = NDR_F_NONE; 9175772Sas200622 9186771Sjb150015 if (size_is > 0) { 9196771Sjb150015 bzero(&myref, sizeof (myref)); 9208334SJose.Borrego@Sun.COM myref.stream = nds; 9216771Sjb150015 myref.enclosing = outer_ref; 9226771Sjb150015 myref.ti = outer_ref->ti; 9236771Sjb150015 myref.datum = outer_ref->datum; 9246771Sjb150015 myref.name = "CONFORMANT-ARRAY"; 9256771Sjb150015 myref.outer_flags = NDR_F_NONE; 9266771Sjb150015 myref.inner_flags = NDR_F_SIZE_IS; 9276771Sjb150015 myref.size_is = outer_ref->size_is; 9286771Sjb150015 9296771Sjb150015 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 9306771Sjb150015 myref.dimension_is = outer_ref->size_is; /* convenient */ 9316771Sjb150015 9326771Sjb150015 myref.pdu_offset = outer_ref->pdu_offset + 4; 9336771Sjb150015 9348334SJose.Borrego@Sun.COM rc = ndr_inner(&myref); 9356771Sjb150015 if (!rc) 9366771Sjb150015 return (rc); /* error already set */ 9376771Sjb150015 } 9385772Sas200622 9398334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 9405772Sas200622 return (1); 9415772Sas200622 } 9425772Sas200622 9435772Sas200622 int 9448334SJose.Borrego@Sun.COM ndr_outer_conformant_construct(ndr_ref_t *outer_ref) 9455772Sas200622 { 9468334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 9478334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 9488334SJose.Borrego@Sun.COM ndr_ref_t myref; 9495772Sas200622 char *valp = NULL; 9505772Sas200622 int is_varlen = ti->pdu_size_variable_part; 9515772Sas200622 int is_union = NDR_IS_UNION(ti); 9525772Sas200622 int is_string = NDR_IS_STRING(ti); 9535772Sas200622 unsigned long size_is; 9545772Sas200622 int rc; 9555772Sas200622 unsigned n_hdr; 9565772Sas200622 unsigned n_fixed; 9575772Sas200622 unsigned n_variable; 9585772Sas200622 unsigned n_alloc; 9595772Sas200622 unsigned n_pdu_total; 9605772Sas200622 int params; 9615772Sas200622 9625772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 9635772Sas200622 9645772Sas200622 assert(is_varlen && !is_string && !is_union); 9655772Sas200622 assert(params == NDR_F_NONE); 9665772Sas200622 9675772Sas200622 /* conformant header for this */ 9685772Sas200622 n_hdr = 4; 9695772Sas200622 9705772Sas200622 /* fixed part -- exactly one of these */ 9715772Sas200622 n_fixed = ti->pdu_size_fixed_part; 9725772Sas200622 9735772Sas200622 /* variable part -- exactly size_of of these */ 9745772Sas200622 n_variable = 0; /* 0 for the moment */ 9755772Sas200622 9765772Sas200622 /* sum them up to determine the PDU space required */ 9775772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 9785772Sas200622 9795772Sas200622 /* similar sum to determine how much local memory is required */ 9805772Sas200622 n_alloc = n_fixed + n_variable; 9815772Sas200622 9825772Sas200622 /* For the moment, grow enough for the fixed-size part */ 9838334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 9845772Sas200622 if (!rc) 9855772Sas200622 return (rc); /* error already set */ 9865772Sas200622 9878334SJose.Borrego@Sun.COM switch (nds->m_op) { 9885772Sas200622 case NDR_M_OP_MARSHALL: 9895772Sas200622 /* 9905772Sas200622 * We don't know the size yet. We have to wait for 9915772Sas200622 * it. Proceed with the fixed-size part, and await 9928334SJose.Borrego@Sun.COM * the call to ndr_size_is(). 9935772Sas200622 */ 9945772Sas200622 size_is = 0; 9958334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 9965772Sas200622 if (!rc) 9975772Sas200622 return (0); /* error already set */ 9985772Sas200622 9995772Sas200622 valp = outer_ref->datum; 10005772Sas200622 assert(valp); 10015772Sas200622 if (outer_ref->backptr) { 10025772Sas200622 assert(valp == *outer_ref->backptr); 10035772Sas200622 } 10045772Sas200622 break; 10055772Sas200622 10065772Sas200622 case NDR_M_OP_UNMARSHALL: 10075772Sas200622 /* 10085772Sas200622 * We know the size of the variable part because 10095772Sas200622 * of the CONFORMANT header. We will verify 10105772Sas200622 * the header against the [size_is(X)] advice 10118334SJose.Borrego@Sun.COM * later when ndr_size_is() is called. 10125772Sas200622 */ 10138334SJose.Borrego@Sun.COM rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 10145772Sas200622 if (!rc) 10155772Sas200622 return (0); /* error already set */ 10165772Sas200622 10175772Sas200622 /* recalculate metrics */ 10185772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 10195772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 10205772Sas200622 n_alloc = n_fixed + n_variable; 10215772Sas200622 10228334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 10235772Sas200622 if (!rc) 10245772Sas200622 return (rc); /* error already set */ 10255772Sas200622 10265772Sas200622 outer_ref->size_is = size_is; /* verified later */ 10275772Sas200622 10288334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref); 10295772Sas200622 if (!valp) { 10305772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 10315772Sas200622 return (0); 10325772Sas200622 } 10335772Sas200622 if (outer_ref->backptr) 10345772Sas200622 *outer_ref->backptr = valp; 10355772Sas200622 outer_ref->datum = valp; 10365772Sas200622 break; 10375772Sas200622 10385772Sas200622 default: 10395772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 10405772Sas200622 return (0); 10415772Sas200622 } 10425772Sas200622 10436771Sjb150015 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 10446771Sjb150015 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 10456771Sjb150015 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 10466771Sjb150015 10475772Sas200622 bzero(&myref, sizeof (myref)); 10488334SJose.Borrego@Sun.COM myref.stream = nds; 10495772Sas200622 myref.enclosing = outer_ref; 10505772Sas200622 myref.ti = outer_ref->ti; 10515772Sas200622 myref.datum = outer_ref->datum; 10525772Sas200622 myref.name = "CONFORMANT-CONSTRUCT"; 10535772Sas200622 myref.outer_flags = NDR_F_NONE; 10545772Sas200622 myref.inner_flags = NDR_F_NONE; 10555772Sas200622 myref.size_is = outer_ref->size_is; 10565772Sas200622 10575772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4; 10585772Sas200622 10598334SJose.Borrego@Sun.COM rc = ndr_inner(&myref); 10605772Sas200622 if (!rc) 10615772Sas200622 return (rc); /* error already set */ 10625772Sas200622 10638334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 10645772Sas200622 10655772Sas200622 if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 10665772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 10675772Sas200622 return (0); 10685772Sas200622 } 10695772Sas200622 10705772Sas200622 return (1); 10715772Sas200622 } 10725772Sas200622 10735772Sas200622 int 10748334SJose.Borrego@Sun.COM ndr_size_is(ndr_ref_t *ref) 10755772Sas200622 { 10768334SJose.Borrego@Sun.COM ndr_stream_t *nds = ref->stream; 10778334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref = nds->outer_current; 10788334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 10795772Sas200622 unsigned long size_is; 10805772Sas200622 int rc; 10815772Sas200622 unsigned n_hdr; 10825772Sas200622 unsigned n_fixed; 10835772Sas200622 unsigned n_variable; 10845772Sas200622 unsigned n_pdu_total; 10855772Sas200622 10865772Sas200622 assert(ref->inner_flags & NDR_F_SIZE_IS); 10875772Sas200622 size_is = ref->size_is; 10885772Sas200622 10895772Sas200622 if (outer_ref->type_flags != NDR_F_SIZE_IS) { 10905772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 10915772Sas200622 return (0); 10925772Sas200622 } 10935772Sas200622 10945772Sas200622 if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 10955772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 10965772Sas200622 return (0); 10975772Sas200622 } 10985772Sas200622 10998334SJose.Borrego@Sun.COM /* repeat metrics, see ndr_conformant_construct() above */ 11005772Sas200622 n_hdr = 4; 11015772Sas200622 n_fixed = ti->pdu_size_fixed_part; 11025772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 11035772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 11045772Sas200622 11058334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 11065772Sas200622 if (!rc) 11075772Sas200622 return (rc); /* error already set */ 11085772Sas200622 11098334SJose.Borrego@Sun.COM switch (nds->m_op) { 11105772Sas200622 case NDR_M_OP_MARSHALL: 11115772Sas200622 /* 11125772Sas200622 * We have to set the sizing header and extend 11135772Sas200622 * the size of the PDU (already done). 11145772Sas200622 */ 11158334SJose.Borrego@Sun.COM rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 11165772Sas200622 if (!rc) 11175772Sas200622 return (0); /* error already set */ 11185772Sas200622 break; 11195772Sas200622 11205772Sas200622 case NDR_M_OP_UNMARSHALL: 11215772Sas200622 /* 11228334SJose.Borrego@Sun.COM * Allocation done during ndr_conformant_construct(). 11235772Sas200622 * All we are doing here is verifying that the 11245772Sas200622 * intended size (ref->size_is) matches the sizing header. 11255772Sas200622 */ 11265772Sas200622 if (size_is != outer_ref->size_is) { 11275772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 11285772Sas200622 return (0); 11295772Sas200622 } 11305772Sas200622 break; 11315772Sas200622 11325772Sas200622 default: 11335772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 11345772Sas200622 return (0); 11355772Sas200622 } 11365772Sas200622 11375772Sas200622 outer_ref->inner_flags |= NDR_F_SIZE_IS; 11385772Sas200622 outer_ref->size_is = ref->size_is; 11395772Sas200622 return (1); 11405772Sas200622 } 11415772Sas200622 11425772Sas200622 int 11438334SJose.Borrego@Sun.COM ndr_outer_string(ndr_ref_t *outer_ref) 11445772Sas200622 { 11458334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 11468334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = outer_ref->ti; 11478334SJose.Borrego@Sun.COM ndr_ref_t myref; 11485772Sas200622 char *valp = NULL; 11495772Sas200622 unsigned is_varlen = ti->pdu_size_variable_part; 11505772Sas200622 int is_union = NDR_IS_UNION(ti); 11515772Sas200622 int is_string = NDR_IS_STRING(ti); 11525772Sas200622 int rc; 11535772Sas200622 unsigned n_zeroes; 11545772Sas200622 unsigned ix; 11555772Sas200622 unsigned long size_is; 11565772Sas200622 unsigned long first_is; 11575772Sas200622 unsigned long length_is; 11585772Sas200622 unsigned n_hdr; 11595772Sas200622 unsigned n_fixed; 11605772Sas200622 unsigned n_variable; 11615772Sas200622 unsigned n_alloc; 11625772Sas200622 unsigned n_pdu_total; 11635772Sas200622 int params; 11645772Sas200622 11655772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 11665772Sas200622 11675772Sas200622 assert(is_varlen && is_string && !is_union); 11685772Sas200622 assert(params == NDR_F_NONE); 11695772Sas200622 11705772Sas200622 /* string header for this: size_is first_is length_is */ 11715772Sas200622 n_hdr = 12; 11725772Sas200622 11735772Sas200622 /* fixed part -- exactly none of these */ 11745772Sas200622 n_fixed = 0; 11755772Sas200622 11768334SJose.Borrego@Sun.COM if (!ndr_outer_grow(outer_ref, n_hdr)) 11775772Sas200622 return (0); /* error already set */ 11785772Sas200622 11798334SJose.Borrego@Sun.COM switch (nds->m_op) { 11805772Sas200622 case NDR_M_OP_MARSHALL: 11815772Sas200622 valp = outer_ref->datum; 11825772Sas200622 assert(valp); 11835772Sas200622 11845772Sas200622 if (outer_ref->backptr) 11855772Sas200622 assert(valp == *outer_ref->backptr); 11865772Sas200622 11875772Sas200622 if (ti == &ndt_s_wchar) { 11885772Sas200622 /* 118910717Samw@Sun.COM * size_is is the number of characters in the 119010717Samw@Sun.COM * (multibyte) string, including the null. 11915772Sas200622 */ 1192*10966SJordan.Brown@Sun.COM size_is = (smb_wcequiv_strlen(valp) / 1193*10966SJordan.Brown@Sun.COM sizeof (smb_wchar_t)) + 1; 11945772Sas200622 11955772Sas200622 if (size_is > NDR_STRING_MAX) { 11965772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 11975772Sas200622 return (0); 11985772Sas200622 } 11995772Sas200622 } else { 12005772Sas200622 valp = outer_ref->datum; 12015772Sas200622 n_zeroes = 0; 12025772Sas200622 for (ix = 0; ix < 1024; ix++) { 12035772Sas200622 if (valp[ix] == 0) { 12045772Sas200622 n_zeroes++; 12055772Sas200622 if (n_zeroes >= is_varlen && 12065772Sas200622 ix % is_varlen == 0) { 12075772Sas200622 break; 12085772Sas200622 } 12095772Sas200622 } else { 12105772Sas200622 n_zeroes = 0; 12115772Sas200622 } 12125772Sas200622 } 12135772Sas200622 if (ix >= 1024) { 12145772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 12155772Sas200622 return (0); 12165772Sas200622 } 12175772Sas200622 size_is = ix+1; 12185772Sas200622 } 12195772Sas200622 12205772Sas200622 first_is = 0; 12215772Sas200622 12228334SJose.Borrego@Sun.COM if (nds->flags & NDS_F_NOTERM) 12235772Sas200622 length_is = size_is - 1; 12245772Sas200622 else 12255772Sas200622 length_is = size_is; 12265772Sas200622 12278334SJose.Borrego@Sun.COM if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) || 12288334SJose.Borrego@Sun.COM !ndr_outer_poke_sizing(outer_ref, 4, &first_is) || 12298334SJose.Borrego@Sun.COM !ndr_outer_poke_sizing(outer_ref, 8, &length_is)) 12305772Sas200622 return (0); /* error already set */ 12315772Sas200622 break; 12325772Sas200622 12335772Sas200622 case NDR_M_OP_UNMARSHALL: 12348334SJose.Borrego@Sun.COM if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) || 12358334SJose.Borrego@Sun.COM !ndr_outer_peek_sizing(outer_ref, 4, &first_is) || 12368334SJose.Borrego@Sun.COM !ndr_outer_peek_sizing(outer_ref, 8, &length_is)) 12375772Sas200622 return (0); /* error already set */ 12385772Sas200622 12395772Sas200622 /* 12405772Sas200622 * In addition to the first_is check, we used to check that 12415772Sas200622 * size_is or size_is-1 was equal to length_is but Windows95 12425772Sas200622 * doesn't conform to this "rule" (see variable part below). 12435772Sas200622 * The srvmgr tool for Windows95 sent the following values 12445772Sas200622 * for a path string: 12455772Sas200622 * 12465772Sas200622 * size_is = 261 (0x105) 12475772Sas200622 * first_is = 0 12485772Sas200622 * length_is = 53 (0x35) 12495772Sas200622 * 12505772Sas200622 * The length_is was correct (for the given path) but the 12515772Sas200622 * size_is was the maximum path length rather than being 12525772Sas200622 * related to length_is. 12535772Sas200622 */ 12545772Sas200622 if (first_is != 0) { 12555772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 12565772Sas200622 return (0); 12575772Sas200622 } 12585772Sas200622 12595772Sas200622 if (ti == &ndt_s_wchar) { 12605772Sas200622 /* 12615772Sas200622 * Decoding Unicode to UTF-8; we need to allow 12625772Sas200622 * for the maximum possible char size. It would 12635772Sas200622 * be nice to use mbequiv_strlen but the string 12645772Sas200622 * may not be null terminated. 12655772Sas200622 */ 12665772Sas200622 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX; 12675772Sas200622 } else { 12685772Sas200622 n_alloc = (size_is + 1) * is_varlen; 12695772Sas200622 } 12705772Sas200622 12718334SJose.Borrego@Sun.COM valp = NDS_MALLOC(nds, n_alloc, outer_ref); 12725772Sas200622 if (!valp) { 12735772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 12745772Sas200622 return (0); 12755772Sas200622 } 12765772Sas200622 12775772Sas200622 bzero(valp, (size_is+1) * is_varlen); 12785772Sas200622 12795772Sas200622 if (outer_ref->backptr) 12805772Sas200622 *outer_ref->backptr = valp; 12815772Sas200622 outer_ref->datum = valp; 12825772Sas200622 break; 12835772Sas200622 12845772Sas200622 default: 12855772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 12865772Sas200622 return (0); 12875772Sas200622 } 12885772Sas200622 12895772Sas200622 /* 12905772Sas200622 * Variable part - exactly length_is of these. 12915772Sas200622 * 12925772Sas200622 * Usually, length_is is same as size_is and includes nul. 12935772Sas200622 * Some protocols use length_is = size_is-1, and length_is does 12945772Sas200622 * not include the nul (which is more consistent with DCE spec). 12955772Sas200622 * If the length_is is 0, there is no data following the 12965772Sas200622 * sizing header, regardless of size_is. 12975772Sas200622 */ 12985772Sas200622 n_variable = length_is * is_varlen; 12995772Sas200622 13005772Sas200622 /* sum them up to determine the PDU space required */ 13015772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 13025772Sas200622 13035772Sas200622 /* similar sum to determine how much local memory is required */ 13045772Sas200622 n_alloc = n_fixed + n_variable; 13055772Sas200622 13068334SJose.Borrego@Sun.COM rc = ndr_outer_grow(outer_ref, n_pdu_total); 13075772Sas200622 if (!rc) 13085772Sas200622 return (rc); /* error already set */ 13095772Sas200622 13105772Sas200622 if (length_is > 0) { 13115772Sas200622 bzero(&myref, sizeof (myref)); 13128334SJose.Borrego@Sun.COM myref.stream = nds; 13135772Sas200622 myref.enclosing = outer_ref; 13145772Sas200622 myref.ti = outer_ref->ti; 13155772Sas200622 myref.datum = outer_ref->datum; 13165772Sas200622 myref.name = "OUTER-STRING"; 13175772Sas200622 myref.outer_flags = NDR_F_IS_STRING; 13185772Sas200622 myref.inner_flags = NDR_F_NONE; 13195772Sas200622 13205772Sas200622 /* 13218334SJose.Borrego@Sun.COM * Set up size_is and strlen_is for ndr_s_wchar. 13225772Sas200622 */ 13235772Sas200622 myref.size_is = size_is; 13245772Sas200622 myref.strlen_is = length_is; 13255772Sas200622 } 13265772Sas200622 13275772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 12; 13285772Sas200622 13295772Sas200622 /* 13305772Sas200622 * Don't try to decode empty strings. 13315772Sas200622 */ 13325772Sas200622 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 13338334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 13345772Sas200622 return (1); 13355772Sas200622 } 13365772Sas200622 13375772Sas200622 if ((size_is != 0) && (length_is != 0)) { 13388334SJose.Borrego@Sun.COM rc = ndr_inner(&myref); 13395772Sas200622 if (!rc) 13405772Sas200622 return (rc); /* error already set */ 13415772Sas200622 } 13425772Sas200622 13438334SJose.Borrego@Sun.COM nds->pdu_scan_offset = outer_ref->pdu_end_offset; 13445772Sas200622 return (1); 13455772Sas200622 } 13465772Sas200622 13475772Sas200622 int 13488334SJose.Borrego@Sun.COM ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset, 13495772Sas200622 unsigned long *sizing_p) 13505772Sas200622 { 13518334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 13528334SJose.Borrego@Sun.COM unsigned long pdu_offset; 13538334SJose.Borrego@Sun.COM int rc; 13545772Sas200622 13555772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 13565772Sas200622 13578334SJose.Borrego@Sun.COM if (pdu_offset < nds->outer_current->pdu_offset || 13588334SJose.Borrego@Sun.COM pdu_offset > nds->outer_current->pdu_end_offset || 13598334SJose.Borrego@Sun.COM pdu_offset+4 > nds->outer_current->pdu_end_offset) { 13605772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 13615772Sas200622 return (0); 13625772Sas200622 } 13635772Sas200622 13648334SJose.Borrego@Sun.COM switch (nds->m_op) { 13655772Sas200622 case NDR_M_OP_MARSHALL: 13665772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 13675772Sas200622 return (0); 13685772Sas200622 13695772Sas200622 case NDR_M_OP_UNMARSHALL: 13708334SJose.Borrego@Sun.COM rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p, 13718334SJose.Borrego@Sun.COM nds->swap, outer_ref); 13725772Sas200622 break; 13735772Sas200622 13745772Sas200622 default: 13755772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 13765772Sas200622 return (0); 13775772Sas200622 } 13785772Sas200622 13795772Sas200622 return (rc); 13805772Sas200622 } 13815772Sas200622 13825772Sas200622 int 13838334SJose.Borrego@Sun.COM ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset, 13845772Sas200622 unsigned long *sizing_p) 13855772Sas200622 { 13868334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 13878334SJose.Borrego@Sun.COM unsigned long pdu_offset; 13888334SJose.Borrego@Sun.COM int rc; 13895772Sas200622 13905772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 13915772Sas200622 13928334SJose.Borrego@Sun.COM if (pdu_offset < nds->outer_current->pdu_offset || 13938334SJose.Borrego@Sun.COM pdu_offset > nds->outer_current->pdu_end_offset || 13948334SJose.Borrego@Sun.COM pdu_offset+4 > nds->outer_current->pdu_end_offset) { 13955772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 13965772Sas200622 return (0); 13975772Sas200622 } 13985772Sas200622 13998334SJose.Borrego@Sun.COM switch (nds->m_op) { 14005772Sas200622 case NDR_M_OP_MARSHALL: 14018334SJose.Borrego@Sun.COM rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14028334SJose.Borrego@Sun.COM nds->swap, outer_ref); 14035772Sas200622 break; 14045772Sas200622 14055772Sas200622 case NDR_M_OP_UNMARSHALL: 14065772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 14075772Sas200622 return (0); 14085772Sas200622 14095772Sas200622 default: 14105772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 14115772Sas200622 return (0); 14125772Sas200622 } 14135772Sas200622 14145772Sas200622 return (rc); 14155772Sas200622 } 14165772Sas200622 14175772Sas200622 /* 14185772Sas200622 * All OUTER constructs begin on a mod4 (dword) boundary - except 14195772Sas200622 * for the ones that don't: some MSRPC calls appear to use word or 14205772Sas200622 * packed alignment. Strings appear to be dword aligned. 14215772Sas200622 */ 14225772Sas200622 int 14238334SJose.Borrego@Sun.COM ndr_outer_align(ndr_ref_t *outer_ref) 14245772Sas200622 { 14258334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 14268334SJose.Borrego@Sun.COM int rc; 14278334SJose.Borrego@Sun.COM unsigned n_pad; 14288334SJose.Borrego@Sun.COM unsigned align; 14295772Sas200622 14305772Sas200622 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 14315772Sas200622 align = outer_ref->ti->alignment; 14328334SJose.Borrego@Sun.COM n_pad = ((align + 1) - nds->pdu_scan_offset) & align; 14335772Sas200622 } else { 14348334SJose.Borrego@Sun.COM n_pad = NDR_ALIGN4(nds->pdu_scan_offset); 14355772Sas200622 } 14365772Sas200622 14375772Sas200622 if (n_pad == 0) 14385772Sas200622 return (1); /* already aligned, often the case */ 14395772Sas200622 14408334SJose.Borrego@Sun.COM if (!ndr_outer_grow(outer_ref, n_pad)) 14415772Sas200622 return (0); /* error already set */ 14425772Sas200622 14438334SJose.Borrego@Sun.COM switch (nds->m_op) { 14445772Sas200622 case NDR_M_OP_MARSHALL: 14458334SJose.Borrego@Sun.COM rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref); 14465772Sas200622 if (!rc) { 14475772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 14485772Sas200622 return (0); 14495772Sas200622 } 14505772Sas200622 break; 14515772Sas200622 14525772Sas200622 case NDR_M_OP_UNMARSHALL: 14535772Sas200622 break; 14545772Sas200622 14555772Sas200622 default: 14565772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 14575772Sas200622 return (0); 14585772Sas200622 } 14595772Sas200622 14608334SJose.Borrego@Sun.COM nds->pdu_scan_offset += n_pad; 14615772Sas200622 return (1); 14625772Sas200622 } 14635772Sas200622 14645772Sas200622 int 14658334SJose.Borrego@Sun.COM ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total) 14665772Sas200622 { 14678334SJose.Borrego@Sun.COM ndr_stream_t *nds = outer_ref->stream; 14688334SJose.Borrego@Sun.COM unsigned long pdu_want_size; 14698334SJose.Borrego@Sun.COM int rc, is_ok = 0; 14705772Sas200622 14718334SJose.Borrego@Sun.COM pdu_want_size = nds->pdu_scan_offset + n_total; 14725772Sas200622 14738334SJose.Borrego@Sun.COM if (pdu_want_size <= nds->pdu_max_size) { 14745772Sas200622 is_ok = 1; 14755772Sas200622 } 14765772Sas200622 14778334SJose.Borrego@Sun.COM switch (nds->m_op) { 14785772Sas200622 case NDR_M_OP_MARSHALL: 14795772Sas200622 if (is_ok) 14805772Sas200622 break; 14818334SJose.Borrego@Sun.COM rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref); 14825772Sas200622 if (!rc) { 14835772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 14845772Sas200622 return (0); 14855772Sas200622 } 14865772Sas200622 break; 14875772Sas200622 14885772Sas200622 case NDR_M_OP_UNMARSHALL: 14895772Sas200622 if (is_ok) 14905772Sas200622 break; 14915772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 14925772Sas200622 return (0); 14935772Sas200622 14945772Sas200622 default: 14955772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 14965772Sas200622 return (0); 14975772Sas200622 } 14985772Sas200622 14998334SJose.Borrego@Sun.COM if (nds->pdu_size < pdu_want_size) 15008334SJose.Borrego@Sun.COM nds->pdu_size = pdu_want_size; 15015772Sas200622 15025772Sas200622 outer_ref->pdu_end_offset = pdu_want_size; 15035772Sas200622 return (1); 15045772Sas200622 } 15055772Sas200622 15065772Sas200622 /* 15075772Sas200622 * INNER ELEMENTS 15085772Sas200622 * 15095772Sas200622 * The local datum (arg_ref->datum) already exists, there is no need to 15105772Sas200622 * malloc() it. The datum should point at a member of a structure. 15115772Sas200622 * 15128334SJose.Borrego@Sun.COM * For the most part, ndr_inner() and its helpers are just a sanity 15135772Sas200622 * check. The underlying ti->ndr_func() could be called immediately 15145772Sas200622 * for non-pointer elements. For the sake of robustness, we detect 15155772Sas200622 * run-time errors here. Most of the situations this protects against 15165772Sas200622 * have already been checked by the IDL compiler. This is also a 15175772Sas200622 * common point for processing of all data, and so is a convenient 15185772Sas200622 * place to work from for debugging. 15195772Sas200622 */ 15205772Sas200622 int 15218334SJose.Borrego@Sun.COM ndr_inner(ndr_ref_t *arg_ref) 15225772Sas200622 { 15238334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = arg_ref->ti; 15245772Sas200622 int is_varlen = ti->pdu_size_variable_part; 15255772Sas200622 int is_union = NDR_IS_UNION(ti); 15265772Sas200622 int error = NDR_ERR_INNER_PARAMS_BAD; 15275772Sas200622 int params; 15285772Sas200622 15295772Sas200622 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 15305772Sas200622 15315772Sas200622 switch (params) { 15325772Sas200622 case NDR_F_NONE: 15335772Sas200622 if (is_union) { 15345772Sas200622 error = NDR_ERR_SWITCH_VALUE_MISSING; 15355772Sas200622 break; 15365772Sas200622 } 15375772Sas200622 return (*ti->ndr_func)(arg_ref); 15385772Sas200622 break; 15395772Sas200622 15405772Sas200622 case NDR_F_SIZE_IS: 15415772Sas200622 case NDR_F_DIMENSION_IS: 15425772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 15435772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 15445772Sas200622 if (is_varlen) { 15455772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 15465772Sas200622 break; 15475772Sas200622 } 15485772Sas200622 if (is_union) { 15495772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15505772Sas200622 break; 15515772Sas200622 } 15525772Sas200622 if (params & NDR_F_IS_POINTER) 15538334SJose.Borrego@Sun.COM return (ndr_inner_pointer(arg_ref)); 15545772Sas200622 else if (params & NDR_F_IS_REFERENCE) 15558334SJose.Borrego@Sun.COM return (ndr_inner_reference(arg_ref)); 15565772Sas200622 else 15578334SJose.Borrego@Sun.COM return (ndr_inner_array(arg_ref)); 15585772Sas200622 break; 15595772Sas200622 15605772Sas200622 case NDR_F_IS_POINTER: /* type is pointer to one something */ 15615772Sas200622 if (is_union) { 15625772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15635772Sas200622 break; 15645772Sas200622 } 15658334SJose.Borrego@Sun.COM return (ndr_inner_pointer(arg_ref)); 15665772Sas200622 break; 15675772Sas200622 15685772Sas200622 case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 15695772Sas200622 if (is_union) { 15705772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15715772Sas200622 break; 15725772Sas200622 } 15738334SJose.Borrego@Sun.COM return (ndr_inner_reference(arg_ref)); 15745772Sas200622 break; 15755772Sas200622 15765772Sas200622 case NDR_F_SWITCH_IS: 15775772Sas200622 if (!is_union) { 15785772Sas200622 error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 15795772Sas200622 break; 15805772Sas200622 } 15815772Sas200622 return (*ti->ndr_func)(arg_ref); 15825772Sas200622 break; 15835772Sas200622 15845772Sas200622 default: 15855772Sas200622 error = NDR_ERR_INNER_PARAMS_BAD; 15865772Sas200622 break; 15875772Sas200622 } 15885772Sas200622 15895772Sas200622 /* 15905772Sas200622 * If we get here, something is wrong. Most likely, 15915772Sas200622 * the params flags do not match 15925772Sas200622 */ 15935772Sas200622 NDR_SET_ERROR(arg_ref, error); 15945772Sas200622 return (0); 15955772Sas200622 } 15965772Sas200622 15975772Sas200622 int 15988334SJose.Borrego@Sun.COM ndr_inner_pointer(ndr_ref_t *arg_ref) 15995772Sas200622 { 16008334SJose.Borrego@Sun.COM ndr_stream_t *nds = arg_ref->stream; 16015772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16028334SJose.Borrego@Sun.COM char **valpp = (char **)arg_ref->datum; 16038334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref; 16045772Sas200622 16058334SJose.Borrego@Sun.COM if (!ndr__ulong(arg_ref)) 16065772Sas200622 return (0); /* error */ 16075772Sas200622 if (!*valpp) 16085772Sas200622 return (1); /* NULL pointer */ 16095772Sas200622 16108334SJose.Borrego@Sun.COM outer_ref = ndr_enter_outer_queue(arg_ref); 16115772Sas200622 if (!outer_ref) 16125772Sas200622 return (0); /* error already set */ 16135772Sas200622 16145772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 16155772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 16165772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 16175772Sas200622 #ifdef NDR_INNER_NOT_YET 16185772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 16195772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 16205772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 16215772Sas200622 } 16225772Sas200622 #endif /* NDR_INNER_NOT_YET */ 16235772Sas200622 16245772Sas200622 outer_ref->backptr = valpp; 16255772Sas200622 16268334SJose.Borrego@Sun.COM switch (nds->m_op) { 16275772Sas200622 case NDR_M_OP_MARSHALL: 16285772Sas200622 outer_ref->datum = *valpp; 16295772Sas200622 break; 16305772Sas200622 16315772Sas200622 case NDR_M_OP_UNMARSHALL: 16325772Sas200622 /* 16335772Sas200622 * This is probably wrong if the application allocated 16345772Sas200622 * memory in advance. Indicate no value for now. 16355772Sas200622 * ONC RPC handles this case. 16365772Sas200622 */ 16375772Sas200622 *valpp = 0; 16385772Sas200622 outer_ref->datum = 0; 16395772Sas200622 break; 16405772Sas200622 } 16415772Sas200622 16425772Sas200622 return (1); /* pointer dereference scheduled */ 16435772Sas200622 } 16445772Sas200622 16455772Sas200622 int 16468334SJose.Borrego@Sun.COM ndr_inner_reference(ndr_ref_t *arg_ref) 16475772Sas200622 { 16488334SJose.Borrego@Sun.COM ndr_stream_t *nds = arg_ref->stream; 16495772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16508334SJose.Borrego@Sun.COM char **valpp = (char **)arg_ref->datum; 16518334SJose.Borrego@Sun.COM ndr_ref_t *outer_ref; 16525772Sas200622 16538334SJose.Borrego@Sun.COM outer_ref = ndr_enter_outer_queue(arg_ref); 16545772Sas200622 if (!outer_ref) 16555772Sas200622 return (0); /* error already set */ 16565772Sas200622 16575772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 16585772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 16595772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 16605772Sas200622 #ifdef NDR_INNER_REF_NOT_YET 16615772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 16625772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 16635772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 16645772Sas200622 } 16655772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */ 16665772Sas200622 16675772Sas200622 outer_ref->backptr = valpp; 16685772Sas200622 16698334SJose.Borrego@Sun.COM switch (nds->m_op) { 16705772Sas200622 case NDR_M_OP_MARSHALL: 16715772Sas200622 outer_ref->datum = *valpp; 16725772Sas200622 break; 16735772Sas200622 16745772Sas200622 case NDR_M_OP_UNMARSHALL: 16755772Sas200622 /* 16765772Sas200622 * This is probably wrong if the application allocated 16775772Sas200622 * memory in advance. Indicate no value for now. 16785772Sas200622 * ONC RPC handles this case. 16795772Sas200622 */ 16805772Sas200622 *valpp = 0; 16815772Sas200622 outer_ref->datum = 0; 16825772Sas200622 break; 16835772Sas200622 } 16845772Sas200622 16855772Sas200622 return (1); /* pointer dereference scheduled */ 16865772Sas200622 } 16875772Sas200622 16885772Sas200622 int 16898334SJose.Borrego@Sun.COM ndr_inner_array(ndr_ref_t *encl_ref) 16905772Sas200622 { 16918334SJose.Borrego@Sun.COM ndr_typeinfo_t *ti = encl_ref->ti; 16928334SJose.Borrego@Sun.COM ndr_ref_t myref; 16935772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 16945772Sas200622 unsigned long n_elem; 16955772Sas200622 unsigned long i; 16965772Sas200622 char name[30]; 16975772Sas200622 16985772Sas200622 if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 16995772Sas200622 /* now is the time to check/set size */ 17008334SJose.Borrego@Sun.COM if (!ndr_size_is(encl_ref)) 17015772Sas200622 return (0); /* error already set */ 17025772Sas200622 n_elem = encl_ref->size_is; 17035772Sas200622 } else { 17045772Sas200622 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 17055772Sas200622 n_elem = encl_ref->dimension_is; 17065772Sas200622 } 17075772Sas200622 17085772Sas200622 bzero(&myref, sizeof (myref)); 17095772Sas200622 myref.enclosing = encl_ref; 17105772Sas200622 myref.stream = encl_ref->stream; 17115772Sas200622 myref.packed_alignment = 0; 17125772Sas200622 myref.ti = ti; 17135772Sas200622 myref.inner_flags = NDR_F_NONE; 17145772Sas200622 17155772Sas200622 for (i = 0; i < n_elem; i++) { 17165772Sas200622 (void) sprintf(name, "[%lu]", i); 17175772Sas200622 myref.name = name; 17185772Sas200622 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 17195772Sas200622 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 17205772Sas200622 17218334SJose.Borrego@Sun.COM if (!ndr_inner(&myref)) 17225772Sas200622 return (0); 17235772Sas200622 } 17245772Sas200622 17255772Sas200622 return (1); 17265772Sas200622 } 17275772Sas200622 17285772Sas200622 17295772Sas200622 /* 17305772Sas200622 * BASIC TYPES 17315772Sas200622 */ 17325772Sas200622 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17338334SJose.Borrego@Sun.COM extern int ndr_##TYPE(struct ndr_reference *encl_ref); \ 17348334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_##TYPE = { \ 17355772Sas200622 1, /* NDR version */ \ 17365772Sas200622 (SIZE)-1, /* alignment */ \ 17375772Sas200622 NDR_F_NONE, /* flags */ \ 17388334SJose.Borrego@Sun.COM ndr_##TYPE, /* ndr_func */ \ 17395772Sas200622 SIZE, /* pdu_size_fixed_part */ \ 17405772Sas200622 0, /* pdu_size_variable_part */ \ 17415772Sas200622 SIZE, /* c_size_fixed_part */ \ 17425772Sas200622 0, /* c_size_variable_part */ \ 17435772Sas200622 }; \ 17448334SJose.Borrego@Sun.COM int ndr_##TYPE(struct ndr_reference *ref) { \ 17458334SJose.Borrego@Sun.COM return (ndr_basic_integer(ref, SIZE)); \ 17465772Sas200622 } 17475772Sas200622 17485772Sas200622 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 17498334SJose.Borrego@Sun.COM extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \ 17508334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_s##TYPE = { \ 17515772Sas200622 1, /* NDR version */ \ 17525772Sas200622 (SIZE)-1, /* alignment */ \ 17535772Sas200622 NDR_F_STRING, /* flags */ \ 17548334SJose.Borrego@Sun.COM ndr_s##TYPE, /* ndr_func */ \ 17555772Sas200622 0, /* pdu_size_fixed_part */ \ 17565772Sas200622 SIZE, /* pdu_size_variable_part */ \ 17575772Sas200622 0, /* c_size_fixed_part */ \ 17585772Sas200622 SIZE, /* c_size_variable_part */ \ 17595772Sas200622 }; \ 17608334SJose.Borrego@Sun.COM int ndr_s##TYPE(struct ndr_reference *ref) { \ 17618334SJose.Borrego@Sun.COM return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \ 17625772Sas200622 } 17635772Sas200622 17645772Sas200622 #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 17655772Sas200622 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17665772Sas200622 MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 17675772Sas200622 17688334SJose.Borrego@Sun.COM int ndr_basic_integer(ndr_ref_t *, unsigned); 17698334SJose.Borrego@Sun.COM int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *); 17705772Sas200622 17715772Sas200622 17725772Sas200622 MAKE_BASIC_TYPE(_char, 1) 17735772Sas200622 MAKE_BASIC_TYPE(_uchar, 1) 17745772Sas200622 MAKE_BASIC_TYPE(_short, 2) 17755772Sas200622 MAKE_BASIC_TYPE(_ushort, 2) 17765772Sas200622 MAKE_BASIC_TYPE(_long, 4) 17775772Sas200622 MAKE_BASIC_TYPE(_ulong, 4) 17785772Sas200622 17795772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2) 17805772Sas200622 17815772Sas200622 int 17828334SJose.Borrego@Sun.COM ndr_basic_integer(ndr_ref_t *ref, unsigned size) 17835772Sas200622 { 17848334SJose.Borrego@Sun.COM ndr_stream_t *nds = ref->stream; 17858334SJose.Borrego@Sun.COM char *valp = (char *)ref->datum; 17868334SJose.Borrego@Sun.COM int rc; 17875772Sas200622 17888334SJose.Borrego@Sun.COM switch (nds->m_op) { 17895772Sas200622 case NDR_M_OP_MARSHALL: 17908334SJose.Borrego@Sun.COM rc = NDS_PUT_PDU(nds, ref->pdu_offset, size, 17918334SJose.Borrego@Sun.COM valp, nds->swap, ref); 17925772Sas200622 break; 17935772Sas200622 17945772Sas200622 case NDR_M_OP_UNMARSHALL: 17958334SJose.Borrego@Sun.COM rc = NDS_GET_PDU(nds, ref->pdu_offset, size, 17968334SJose.Borrego@Sun.COM valp, nds->swap, ref); 17975772Sas200622 break; 17985772Sas200622 17995772Sas200622 default: 18005772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 18015772Sas200622 return (0); 18025772Sas200622 } 18035772Sas200622 18045772Sas200622 return (rc); 18055772Sas200622 } 18065772Sas200622 18075772Sas200622 int 18088334SJose.Borrego@Sun.COM ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under) 18095772Sas200622 { 18105772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 18115772Sas200622 unsigned size = type_under->pdu_size_fixed_part; 18125772Sas200622 char *valp; 18138334SJose.Borrego@Sun.COM ndr_ref_t myref; 18145772Sas200622 unsigned long i; 18155772Sas200622 long sense = 0; 18165772Sas200622 char name[30]; 18175772Sas200622 18185772Sas200622 assert(size != 0); 18195772Sas200622 18205772Sas200622 bzero(&myref, sizeof (myref)); 18215772Sas200622 myref.enclosing = encl_ref; 18225772Sas200622 myref.stream = encl_ref->stream; 18235772Sas200622 myref.packed_alignment = 0; 18245772Sas200622 myref.ti = type_under; 18255772Sas200622 myref.inner_flags = NDR_F_NONE; 18265772Sas200622 myref.name = name; 18275772Sas200622 18285772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 18295772Sas200622 (void) sprintf(name, "[%lu]", i); 18305772Sas200622 myref.pdu_offset = pdu_offset + i * size; 18315772Sas200622 valp = encl_ref->datum + i * size; 18325772Sas200622 myref.datum = valp; 18335772Sas200622 18348334SJose.Borrego@Sun.COM if (!ndr_inner(&myref)) 18355772Sas200622 return (0); 18365772Sas200622 18375772Sas200622 switch (size) { 18385772Sas200622 case 1: sense = *valp; break; 18395772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 18405772Sas200622 case 2: sense = *(short *)valp; break; 18415772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 18425772Sas200622 case 4: sense = *(long *)valp; break; 18435772Sas200622 } 18445772Sas200622 18455772Sas200622 if (!sense) 18465772Sas200622 break; 18475772Sas200622 } 18485772Sas200622 18495772Sas200622 return (1); 18505772Sas200622 } 18515772Sas200622 18525772Sas200622 18538334SJose.Borrego@Sun.COM extern int ndr_s_wchar(ndr_ref_t *encl_ref); 18548334SJose.Borrego@Sun.COM ndr_typeinfo_t ndt_s_wchar = { 18555772Sas200622 1, /* NDR version */ 18565772Sas200622 2-1, /* alignment */ 18575772Sas200622 NDR_F_STRING, /* flags */ 18588334SJose.Borrego@Sun.COM ndr_s_wchar, /* ndr_func */ 18595772Sas200622 0, /* pdu_size_fixed_part */ 18605772Sas200622 2, /* pdu_size_variable_part */ 18615772Sas200622 0, /* c_size_fixed_part */ 18625772Sas200622 1, /* c_size_variable_part */ 18635772Sas200622 }; 18645772Sas200622 18655772Sas200622 18665772Sas200622 /* 18675772Sas200622 * Hand coded wchar function because all strings are transported 18685772Sas200622 * as wide characters. During NDR_M_OP_MARSHALL, we convert from 18695772Sas200622 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 18705772Sas200622 * convert from wide characters to multi-byte. 18715772Sas200622 * 18725772Sas200622 * It appeared that NT would sometimes leave a spurious character 18735772Sas200622 * in the data stream before the null wide_char, which would get 18745772Sas200622 * included in the string decode because we processed until the 18755772Sas200622 * null character. It now looks like NT does not always terminate 18765772Sas200622 * RPC Unicode strings and the terminating null is a side effect 18775772Sas200622 * of field alignment. So now we rely on the strlen_is (set up in 18788334SJose.Borrego@Sun.COM * ndr_outer_string) of the enclosing reference. This may or may 18795772Sas200622 * not include the null but it doesn't matter, the algorithm will 18805772Sas200622 * get it right. 18815772Sas200622 */ 18825772Sas200622 int 18838334SJose.Borrego@Sun.COM ndr_s_wchar(ndr_ref_t *encl_ref) 18845772Sas200622 { 18858334SJose.Borrego@Sun.COM ndr_stream_t *nds = encl_ref->stream; 18865772Sas200622 unsigned short wide_char; 18875772Sas200622 char *valp; 18888334SJose.Borrego@Sun.COM ndr_ref_t myref; 18895772Sas200622 unsigned long i; 18905772Sas200622 char name[30]; 18915772Sas200622 int count; 18925772Sas200622 int char_count = 0; 18935772Sas200622 18948334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_UNMARSHALL) { 18955772Sas200622 /* 18965772Sas200622 * To avoid problems with zero length strings 18975772Sas200622 * we can just null terminate here and be done. 18985772Sas200622 */ 18995772Sas200622 if (encl_ref->strlen_is == 0) { 19005772Sas200622 encl_ref->datum[0] = '\0'; 19015772Sas200622 return (1); 19025772Sas200622 } 19035772Sas200622 } 19045772Sas200622 19055772Sas200622 bzero(&myref, sizeof (myref)); 19065772Sas200622 myref.enclosing = encl_ref; 19075772Sas200622 myref.stream = encl_ref->stream; 19085772Sas200622 myref.packed_alignment = 0; 19095772Sas200622 myref.ti = &ndt__wchar; 19105772Sas200622 myref.inner_flags = NDR_F_NONE; 19115772Sas200622 myref.datum = (char *)&wide_char; 19125772Sas200622 myref.name = name; 19135772Sas200622 myref.pdu_offset = encl_ref->pdu_offset; 19145772Sas200622 19155772Sas200622 valp = encl_ref->datum; 19165772Sas200622 count = 0; 19175772Sas200622 19185772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 19195772Sas200622 (void) sprintf(name, "[%lu]", i); 19205772Sas200622 19218334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_MARSHALL) { 1922*10966SJordan.Brown@Sun.COM count = smb_mbtowc((smb_wchar_t *)&wide_char, valp, 19235772Sas200622 MTS_MB_CHAR_MAX); 19245772Sas200622 if (count < 0) { 19255772Sas200622 return (0); 19265772Sas200622 } else if (count == 0) { 19275772Sas200622 if (encl_ref->strlen_is != encl_ref->size_is) 19285772Sas200622 break; 19295772Sas200622 19305772Sas200622 /* 19315772Sas200622 * If the input char is 0, mbtowc 19325772Sas200622 * returns 0 without setting wide_char. 19335772Sas200622 * Set wide_char to 0 and a count of 1. 19345772Sas200622 */ 19355772Sas200622 wide_char = *valp; 19365772Sas200622 count = 1; 19375772Sas200622 } 19385772Sas200622 } 19395772Sas200622 19408334SJose.Borrego@Sun.COM if (!ndr_inner(&myref)) 19415772Sas200622 return (0); 19425772Sas200622 19438334SJose.Borrego@Sun.COM if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1944*10966SJordan.Brown@Sun.COM count = smb_wctomb(valp, wide_char); 19455772Sas200622 19465772Sas200622 if ((++char_count) == encl_ref->strlen_is) { 19475772Sas200622 valp += count; 19485772Sas200622 *valp = '\0'; 19495772Sas200622 break; 19505772Sas200622 } 19515772Sas200622 } 19525772Sas200622 19535772Sas200622 if (!wide_char) 19545772Sas200622 break; 19555772Sas200622 19565772Sas200622 myref.pdu_offset += sizeof (wide_char); 19575772Sas200622 valp += count; 19585772Sas200622 } 19595772Sas200622 19605772Sas200622 return (1); 19615772Sas200622 } 19625772Sas200622 19635772Sas200622 /* 19645772Sas200622 * Converts a multibyte character string to a little-endian, wide-char 19655772Sas200622 * string. No more than nwchars wide characters are stored. 19665772Sas200622 * A terminating null wide character is appended if there is room. 19675772Sas200622 * 19685772Sas200622 * Returns the number of wide characters converted, not counting 19695772Sas200622 * any terminating null wide character. Returns -1 if an invalid 19705772Sas200622 * multibyte character is encountered. 19715772Sas200622 */ 19725772Sas200622 size_t 1973*10966SJordan.Brown@Sun.COM ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs, 19745772Sas200622 size_t nwchars) 19755772Sas200622 { 1976*10966SJordan.Brown@Sun.COM smb_wchar_t *start = wcs; 19775772Sas200622 int nbytes; 19785772Sas200622 19795772Sas200622 while (nwchars--) { 19808334SJose.Borrego@Sun.COM nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX); 19815772Sas200622 if (nbytes < 0) { 19825772Sas200622 *wcs = 0; 19835772Sas200622 return ((size_t)-1); 19845772Sas200622 } 19855772Sas200622 19865772Sas200622 if (*mbs == 0) 19875772Sas200622 break; 19885772Sas200622 19895772Sas200622 ++wcs; 19905772Sas200622 mbs += nbytes; 19915772Sas200622 } 19925772Sas200622 19935772Sas200622 return (wcs - start); 19945772Sas200622 } 19955772Sas200622 19965772Sas200622 /* 19975772Sas200622 * Converts a multibyte character to a little-endian, wide-char, which 19985772Sas200622 * is stored in wcharp. Up to nbytes bytes are examined. 19995772Sas200622 * 20005772Sas200622 * If mbchar is valid, returns the number of bytes processed in mbchar. 2001*10966SJordan.Brown@Sun.COM * If mbchar is invalid, returns -1. See also smb_mbtowc(). 20025772Sas200622 */ 20035772Sas200622 /*ARGSUSED*/ 20045772Sas200622 int 2005*10966SJordan.Brown@Sun.COM ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar, 20068334SJose.Borrego@Sun.COM size_t nbytes) 20075772Sas200622 { 20085772Sas200622 int rc; 20095772Sas200622 2010*10966SJordan.Brown@Sun.COM if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0) 20115772Sas200622 return (rc); 20125772Sas200622 20135772Sas200622 #ifdef _BIG_ENDIAN 20148334SJose.Borrego@Sun.COM if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) 20155772Sas200622 *wcharp = BSWAP_16(*wcharp); 20165772Sas200622 #endif 20175772Sas200622 20185772Sas200622 return (rc); 20195772Sas200622 } 2020