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 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 #pragma ident "%Z%%M% %I% %E% SMI" 275772Sas200622 285772Sas200622 /* 295772Sas200622 * Network Data Representation (NDR) is a compatible subset of the DCE RPC 305772Sas200622 * and MSRPC NDR. NDR is used to move parameters consisting of 315772Sas200622 * complicated trees of data constructs between an RPC client and server. 325772Sas200622 */ 335772Sas200622 345772Sas200622 #include <sys/byteorder.h> 355772Sas200622 #include <strings.h> 365772Sas200622 #include <assert.h> 375772Sas200622 #include <string.h> 385772Sas200622 #include <stdlib.h> 395772Sas200622 405772Sas200622 #include <smbsrv/libsmb.h> 415772Sas200622 #include <smbsrv/string.h> 425772Sas200622 #include <smbsrv/ndr.h> 435772Sas200622 445772Sas200622 #define NDR_STRING_MAX 256 455772Sas200622 465772Sas200622 #define NDR_IS_UNION(T) \ 475772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION) 485772Sas200622 #define NDR_IS_STRING(T) \ 495772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING) 505772Sas200622 515772Sas200622 extern struct ndr_typeinfo ndt_s_wchar; 525772Sas200622 535772Sas200622 /* 545772Sas200622 * The following synopsis describes the terms TOP-MOST, OUTER and INNER. 555772Sas200622 * 565772Sas200622 * Each parameter (call arguments and return values) is a TOP-MOST item. 575772Sas200622 * A TOP-MOST item consists of one or more OUTER items. An OUTER item 585772Sas200622 * consists of one or more INNER items. There are important differences 595772Sas200622 * between each kind, which, primarily, have to do with the allocation 605772Sas200622 * of memory to contain data structures and the order of processing. 615772Sas200622 * 625772Sas200622 * This is most easily demonstrated with a short example. 635772Sas200622 * Consider these structures: 645772Sas200622 * 655772Sas200622 * struct top_param { 665772Sas200622 * long level; 675772Sas200622 * struct list * head; 685772Sas200622 * long count; 695772Sas200622 * }; 705772Sas200622 * 715772Sas200622 * struct list { 725772Sas200622 * struct list * next; 735772Sas200622 * char * str; // a string 745772Sas200622 * }; 755772Sas200622 * 765772Sas200622 * Now, consider an instance tree like this: 775772Sas200622 * 785772Sas200622 * +---------+ +-------+ +-------+ 795772Sas200622 * |top_param| +--->|list #1| +--->|list #2| 805772Sas200622 * +---------+ | +-------+ | +-------+ 815772Sas200622 * | level | | | next ----+ | next --->(NULL) 825772Sas200622 * | head ----+ | str -->"foo" | str -->"bar" 835772Sas200622 * | count | | flag | | flag | 845772Sas200622 * +---------+ +-------+ +-------+ 855772Sas200622 * 865772Sas200622 * The DCE(MS)/RPC Stub Data encoding for the tree is the following. 875772Sas200622 * The vertical bars (|) indicate OUTER construct boundaries. 885772Sas200622 * 895772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 905772Sas200622 * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count| 915772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 925772Sas200622 * level |<----------------------- head -------------------------->|count 935772Sas200622 * TOP TOP TOP 945772Sas200622 * 955772Sas200622 * Here's what to notice: 965772Sas200622 * 975772Sas200622 * - The members of the TOP-MOST construct are scattered through the Stub 985772Sas200622 * Data in the order they occur. This example shows a TOP-MOST construct 995772Sas200622 * consisting of atomic types (pointers and integers). A construct 1005772Sas200622 * (struct) within the TOP-MOST construct would be contiguous and not 1015772Sas200622 * scattered. 1025772Sas200622 * 1035772Sas200622 * - The members of OUTER constructs are contiguous, which allows for 1045772Sas200622 * non-copied relocated (fixed-up) data structures at the packet's 1055772Sas200622 * destination. We don't do fix-ups here. The pointers within the 1065772Sas200622 * OUTER constructs are processed depth-first in the order that they 1075772Sas200622 * occur. If they were processed breadth first, the sequence would 1085772Sas200622 * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may 1095772Sas200622 * be variable length, and pointers are often encountered before the 1105772Sas200622 * size(s) is known. 1115772Sas200622 * 1125772Sas200622 * - The INNER constructs are simply the members of an OUTER construct. 1135772Sas200622 * 1145772Sas200622 * For comparison, consider how ONC RPC would handle the same tree of 1155772Sas200622 * data. ONC requires very little buffering, while DCE requires enough 1165772Sas200622 * buffer space for the entire message. ONC does atom-by-atom depth-first 1175772Sas200622 * (de)serialization and copy, while DCE allows for constructs to be 1185772Sas200622 * "fixed-up" (relocated) in place at the destination. The packet data 1195772Sas200622 * for the same tree processed by ONC RPC would look like this: 1205772Sas200622 * 1215772Sas200622 * +---------------------------------------------------------------------+ 1225772Sas200622 * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count| 1235772Sas200622 * +---------------------------------------------------------------------+ 1245772Sas200622 * TOP #1 #2 #2 bar #2 #1 foo #1 TOP 1255772Sas200622 * 1265772Sas200622 * More details about each TOP-MOST, OUTER, and INNER constructs appear 1275772Sas200622 * throughout this source file near where such constructs are processed. 1285772Sas200622 * 1295772Sas200622 * NDR_REFERENCE 1305772Sas200622 * 1315772Sas200622 * The primary object for NDR is the struct ndr_reference. 1325772Sas200622 * 1335772Sas200622 * An ndr_reference indicates the local datum (i.e. native "C" data 1345772Sas200622 * format), and the element within the Stub Data (contained within the 1355772Sas200622 * RPC PDU (protocol data unit). An ndr_reference also indicates, 1365772Sas200622 * largely as a debugging aid, something about the type of the 1375772Sas200622 * element/datum, and the enclosing construct for the element. The 1385772Sas200622 * ndr_reference's are typically allocated on the stack as locals, 1395772Sas200622 * and the chain of ndr_reference.enclosing references is in reverse 1405772Sas200622 * order of the call graph. 1415772Sas200622 * 1425772Sas200622 * The ndr_reference.datum is a pointer to the local memory that 1435772Sas200622 * contains/receives the value. The ndr_reference.pdu_offset indicates 1445772Sas200622 * where in the Stub Data the value is to be stored/retrieved. 1455772Sas200622 * 1465772Sas200622 * The ndr_reference also contains various parameters to the NDR 1475772Sas200622 * process, such as ndr_reference.size_is, which indicates the size 1485772Sas200622 * of variable length data, or ndr_reference.switch_is, which 1495772Sas200622 * indicates the arm of a union to use. 1505772Sas200622 * 1515772Sas200622 * QUEUE OF OUTER REFERENCES 1525772Sas200622 * 1535772Sas200622 * Some OUTER constructs are variable size. Sometimes (often) we don't 1545772Sas200622 * know the size of the OUTER construct until after pointers have been 1555772Sas200622 * encountered. Hence, we can not begin processing the referent of the 1565772Sas200622 * pointer until after the referring OUTER construct is completely 1575772Sas200622 * processed, i.e. we don't know where to find/put the referent in the 1585772Sas200622 * Stub Data until we know the size of all its predecessors. 1595772Sas200622 * 1605772Sas200622 * This is managed using the queue of OUTER references. The queue is 1615772Sas200622 * anchored in mlndr_stream.outer_queue_head. At any time, 1625772Sas200622 * mlndr_stream.outer_queue_tailp indicates where to put the 1635772Sas200622 * ndr_reference for the next encountered pointer. 1645772Sas200622 * 1655772Sas200622 * Refer to the example above as we illustrate the queue here. In these 1665772Sas200622 * illustrations, the queue entries are not the data structures themselves. 1675772Sas200622 * Rather, they are ndr_reference entries which **refer** to the data 1685772Sas200622 * structures in both the PDU and local memory. 1695772Sas200622 * 1705772Sas200622 * During some point in the processing, the queue looks like this: 1715772Sas200622 * 1725772Sas200622 * outer_current -------v 1735772Sas200622 * outer_queue_head --> list#1 --0 1745772Sas200622 * outer_queue_tailp ---------& 1755772Sas200622 * 1765772Sas200622 * When the pointer #1.next is encountered, and entry is added to the 1775772Sas200622 * queue, 1785772Sas200622 * 1795772Sas200622 * outer_current -------v 1805772Sas200622 * outer_queue_head --> list#1 --> list#2 --0 1815772Sas200622 * outer_queue_tailp --------------------& 1825772Sas200622 * 1835772Sas200622 * and the members of #1 continue to be processed, which encounters 1845772Sas200622 * #1.str: 1855772Sas200622 * 1865772Sas200622 * outer_current -------v 1875772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 1885772Sas200622 * outer_queue_tailp ------------------------------& 1895772Sas200622 * 1905772Sas200622 * Upon the completion of list#1, the processing continues by moving 1915772Sas200622 * to mlndr_stream.outer_current->next, and the tail is set to this 1925772Sas200622 * outer member: 1935772Sas200622 * 1945772Sas200622 * outer_current ------------------v 1955772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 1965772Sas200622 * outer_queue_tailp --------------------& 1975772Sas200622 * 1985772Sas200622 * Space for list#2 is allocated, either in the Stub Data or of local 1995772Sas200622 * memory. When #2.next is encountered, it is found to be the null 2005772Sas200622 * pointer and no reference is added to the queue. When #2.str is 2015772Sas200622 * encountered, it is found to be valid, and a reference is added: 2025772Sas200622 * 2035772Sas200622 * outer_current ------------------v 2045772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 2055772Sas200622 * outer_queue_tailp ------------------------------& 2065772Sas200622 * 2075772Sas200622 * Processing continues in a similar fashion with the string "bar", 2085772Sas200622 * which is variable-length. At this point, memory for "bar" may be 2095772Sas200622 * malloc()ed during NDR_M_OP_UNMARSHALL: 2105772Sas200622 * 2115772Sas200622 * outer_current -----------------------------v 2125772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 2135772Sas200622 * outer_queue_tailp ------------------------------& 2145772Sas200622 * 2155772Sas200622 * And finishes on string "foo". Notice that because "bar" is a 2165772Sas200622 * variable length string, and we don't know the PDU offset for "foo" 2175772Sas200622 * until we reach this point. 2185772Sas200622 * 2195772Sas200622 * When the queue is drained (current->next==0), processing continues 2205772Sas200622 * with the next TOP-MOST member. 2215772Sas200622 * 2225772Sas200622 * The queue of OUTER constructs manages the variable-length semantics 2235772Sas200622 * of OUTER constructs and satisfies the depth-first requirement. 2245772Sas200622 * We allow the queue to linger until the entire TOP-MOST structure is 2255772Sas200622 * processed as an aid to debugging. 2265772Sas200622 */ 2275772Sas200622 2285772Sas200622 static struct ndr_reference *mlndr_enter_outer_queue(struct ndr_reference *); 2295772Sas200622 extern int mlndr__ulong(struct ndr_reference *); 2305772Sas200622 2315772Sas200622 /* 2325772Sas200622 * TOP-MOST ELEMENTS 2335772Sas200622 * 2345772Sas200622 * This is fundamentally the first OUTER construct of the parameter, 2355772Sas200622 * possibly followed by more OUTER constructs due to pointers. The 2365772Sas200622 * datum (local memory) for TOP-MOST constructs (structs) is allocated 2375772Sas200622 * by the caller of NDR. 2385772Sas200622 * 2395772Sas200622 * After the element is transferred, the outer_queue is drained. 2405772Sas200622 * 2415772Sas200622 * All we have to do is add an entry to the outer_queue for this 2425772Sas200622 * top-most member, and commence the outer_queue processing. 2435772Sas200622 */ 2445772Sas200622 int 2455772Sas200622 mlndo_process(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti, 2465772Sas200622 char *datum) 2475772Sas200622 { 2485772Sas200622 struct ndr_reference myref; 2495772Sas200622 2505772Sas200622 bzero(&myref, sizeof (myref)); 2515772Sas200622 myref.stream = mlnds; 2525772Sas200622 myref.datum = datum; 2535772Sas200622 myref.name = "PROCESS"; 2545772Sas200622 myref.ti = ti; 2555772Sas200622 2565772Sas200622 return (mlndr_topmost(&myref)); 2575772Sas200622 } 2585772Sas200622 2595772Sas200622 int 2605772Sas200622 mlndo_operation(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti, 2615772Sas200622 int opnum, char *datum) 2625772Sas200622 { 2635772Sas200622 struct ndr_reference myref; 2645772Sas200622 2655772Sas200622 bzero(&myref, sizeof (myref)); 2665772Sas200622 myref.stream = mlnds; 2675772Sas200622 myref.datum = datum; 2685772Sas200622 myref.name = "OPERATION"; 2695772Sas200622 myref.ti = ti; 2705772Sas200622 myref.inner_flags = NDR_F_SWITCH_IS; 2715772Sas200622 myref.switch_is = opnum; 2725772Sas200622 2735772Sas200622 if (ti->type_flags != NDR_F_INTERFACE) { 2745772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE); 2755772Sas200622 return (0); 2765772Sas200622 } 2775772Sas200622 2785772Sas200622 return ((*ti->ndr_func)(&myref)); 2795772Sas200622 } 2805772Sas200622 2815772Sas200622 int 2825772Sas200622 mlndr_params(struct ndr_reference *params_ref) 2835772Sas200622 { 2845772Sas200622 struct ndr_typeinfo *ti = params_ref->ti; 2855772Sas200622 2865772Sas200622 if (ti->type_flags == NDR_F_OPERATION) 2875772Sas200622 return (*ti->ndr_func) (params_ref); 2885772Sas200622 else 2895772Sas200622 return (mlndr_topmost(params_ref)); 2905772Sas200622 } 2915772Sas200622 2925772Sas200622 int 2935772Sas200622 mlndr_topmost(struct ndr_reference *top_ref) 2945772Sas200622 { 2955772Sas200622 struct mlndr_stream *mlnds; 2965772Sas200622 struct ndr_typeinfo *ti; 2975772Sas200622 struct ndr_reference *outer_ref = 0; 2985772Sas200622 int is_varlen; 2995772Sas200622 int is_string; 3005772Sas200622 int error; 3015772Sas200622 int rc; 3025772Sas200622 unsigned n_fixed; 3035772Sas200622 int params; 3045772Sas200622 3055772Sas200622 assert(top_ref); 3065772Sas200622 assert(top_ref->stream); 3075772Sas200622 assert(top_ref->ti); 3085772Sas200622 3095772Sas200622 mlnds = top_ref->stream; 3105772Sas200622 ti = top_ref->ti; 3115772Sas200622 3125772Sas200622 is_varlen = ti->pdu_size_variable_part; 3135772Sas200622 is_string = NDR_IS_STRING(ti); 3145772Sas200622 3155772Sas200622 assert(mlnds->outer_queue_tailp && !*mlnds->outer_queue_tailp); 3165772Sas200622 assert(!mlnds->outer_current); 3175772Sas200622 3185772Sas200622 params = top_ref->inner_flags & NDR_F_PARAMS_MASK; 3195772Sas200622 3205772Sas200622 switch (params) { 3215772Sas200622 case NDR_F_NONE: 3225772Sas200622 case NDR_F_SWITCH_IS: 3235772Sas200622 if (is_string || is_varlen) { 3245772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 3255772Sas200622 NDR_SET_ERROR(outer_ref, error); 3265772Sas200622 return (0); 3275772Sas200622 } 3285772Sas200622 n_fixed = ti->pdu_size_fixed_part; 3295772Sas200622 break; 3305772Sas200622 3315772Sas200622 case NDR_F_SIZE_IS: 3325772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 3335772Sas200622 NDR_SET_ERROR(outer_ref, error); 3345772Sas200622 return (0); 3355772Sas200622 3365772Sas200622 case NDR_F_DIMENSION_IS: 3375772Sas200622 if (is_varlen) { 3385772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 3395772Sas200622 NDR_SET_ERROR(outer_ref, error); 3405772Sas200622 return (0); 3415772Sas200622 } 3425772Sas200622 n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is; 3435772Sas200622 break; 3445772Sas200622 3455772Sas200622 case NDR_F_IS_POINTER: 3465772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 3475772Sas200622 n_fixed = 4; 3485772Sas200622 break; 3495772Sas200622 3505772Sas200622 case NDR_F_IS_REFERENCE: 3515772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 3525772Sas200622 n_fixed = 0; 3535772Sas200622 break; 3545772Sas200622 3555772Sas200622 default: 3565772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 3575772Sas200622 NDR_SET_ERROR(outer_ref, error); 3585772Sas200622 return (0); 3595772Sas200622 } 3605772Sas200622 3615772Sas200622 outer_ref = mlndr_enter_outer_queue(top_ref); 3625772Sas200622 if (!outer_ref) 3635772Sas200622 return (0); /* error already set */ 3645772Sas200622 3655772Sas200622 /* 3665772Sas200622 * Hand-craft the first OUTER construct and directly call 3675772Sas200622 * mlndr_inner(). Then, run the outer_queue. We do this 3685772Sas200622 * because mlndr_outer() wants to malloc() memory for 3695772Sas200622 * the construct, and we already have the memory. 3705772Sas200622 */ 3715772Sas200622 3725772Sas200622 /* move the flags, etc, around again, undoes enter_outer_queue() */ 3735772Sas200622 outer_ref->inner_flags = top_ref->inner_flags; 3745772Sas200622 outer_ref->outer_flags = 0; 3755772Sas200622 outer_ref->datum = top_ref->datum; 3765772Sas200622 3775772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 3785772Sas200622 if (!mlndr_outer_align(outer_ref)) 3795772Sas200622 return (0); /* error already set */ 3805772Sas200622 3815772Sas200622 /* Regardless of what it is, this is where it starts */ 3825772Sas200622 outer_ref->pdu_offset = mlnds->pdu_scan_offset; 3835772Sas200622 3845772Sas200622 rc = mlndr_outer_grow(outer_ref, n_fixed); 3855772Sas200622 if (!rc) 3865772Sas200622 return (0); /* error already set */ 3875772Sas200622 3885772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed; 3895772Sas200622 3905772Sas200622 /* set-up outer_current, as though run_outer_queue() was doing it */ 3915772Sas200622 mlnds->outer_current = outer_ref; 3925772Sas200622 mlnds->outer_queue_tailp = &mlnds->outer_current->next; 3935772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 3945772Sas200622 3955772Sas200622 /* do the topmost member */ 3965772Sas200622 rc = mlndr_inner(outer_ref); 3975772Sas200622 if (!rc) 3985772Sas200622 return (0); /* error already set */ 3995772Sas200622 4005772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 4015772Sas200622 4025772Sas200622 /* advance, as though run_outer_queue() was doing it */ 4035772Sas200622 mlnds->outer_current = mlnds->outer_current->next; 4045772Sas200622 return (mlndr_run_outer_queue(mlnds)); 4055772Sas200622 } 4065772Sas200622 4075772Sas200622 static struct ndr_reference * 4085772Sas200622 mlndr_enter_outer_queue(struct ndr_reference *arg_ref) 4095772Sas200622 { 4105772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 4115772Sas200622 struct ndr_reference *outer_ref; 4125772Sas200622 4135772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 4145772Sas200622 outer_ref = (struct ndr_reference *) 4155772Sas200622 MLNDS_MALLOC(mlnds, sizeof (*outer_ref), arg_ref); 4165772Sas200622 if (!outer_ref) { 4175772Sas200622 NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED); 4185772Sas200622 return (0); 4195772Sas200622 } 4205772Sas200622 4215772Sas200622 *outer_ref = *arg_ref; 4225772Sas200622 4235772Sas200622 /* move advice in inner_flags to outer_flags */ 4245772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 4255772Sas200622 outer_ref->inner_flags = 0; 4265772Sas200622 outer_ref->enclosing = mlnds->outer_current; 4275772Sas200622 outer_ref->backptr = 0; 4285772Sas200622 outer_ref->datum = 0; 4295772Sas200622 4305772Sas200622 assert(mlnds->outer_queue_tailp); 4315772Sas200622 4325772Sas200622 outer_ref->next = *mlnds->outer_queue_tailp; 4335772Sas200622 *mlnds->outer_queue_tailp = outer_ref; 4345772Sas200622 mlnds->outer_queue_tailp = &outer_ref->next; 4355772Sas200622 return (outer_ref); 4365772Sas200622 } 4375772Sas200622 4385772Sas200622 int 4395772Sas200622 mlndr_run_outer_queue(struct mlndr_stream *mlnds) 4405772Sas200622 { 4415772Sas200622 while (mlnds->outer_current) { 4425772Sas200622 mlnds->outer_queue_tailp = &mlnds->outer_current->next; 4435772Sas200622 4445772Sas200622 if (!mlndr_outer(mlnds->outer_current)) 4455772Sas200622 return (0); 4465772Sas200622 4475772Sas200622 mlnds->outer_current = mlnds->outer_current->next; 4485772Sas200622 } 4495772Sas200622 4505772Sas200622 return (1); 4515772Sas200622 } 4525772Sas200622 4535772Sas200622 /* 4545772Sas200622 * OUTER CONSTRUCTS 4555772Sas200622 * 4565772Sas200622 * OUTER constructs are where the real work is, which stems from the 4575772Sas200622 * variable-length potential. 4585772Sas200622 * 4595772Sas200622 * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT 4605772Sas200622 * 4615772Sas200622 * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT, 4625772Sas200622 * VARYING, and VARYING/CONFORMANT. 4635772Sas200622 * 4645772Sas200622 * What makes this so tough is that the variable-length array may be well 4655772Sas200622 * encapsulated within the outer construct. Further, because DCE(MS)/RPC 4665772Sas200622 * tries to keep the constructs contiguous in the data stream, the sizing 4675772Sas200622 * information precedes the entire OUTER construct. The sizing information 4685772Sas200622 * must be used at the appropriate time, which can be after many, many, 4695772Sas200622 * many fixed-length elements. During IDL type analysis, we know in 4705772Sas200622 * advance constructs that encapsulate variable-length constructs. So, 4715772Sas200622 * we know when we have a sizing header and when we don't. The actual 4725772Sas200622 * semantics of the header are largely deferred. 4735772Sas200622 * 4745772Sas200622 * Currently, VARYING constructs are not implemented but they are described 4755772Sas200622 * here in case they have to be implemented in the future. Similarly, 4765772Sas200622 * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently 4775772Sas200622 * not implemented. Only one-dimensional, variable-length arrays are 4785772Sas200622 * supported. 4795772Sas200622 * 4805772Sas200622 * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW 4815772Sas200622 * 4825772Sas200622 * All variable-length values are arrays. These arrays may be embedded 4835772Sas200622 * well within another construct. However, a variable-length construct 4845772Sas200622 * may ONLY appear as the last member of an enclosing construct. Example: 4855772Sas200622 * 4865772Sas200622 * struct credentials { 4875772Sas200622 * ulong uid, gid; 4885772Sas200622 * ulong n_gids; 4895772Sas200622 * [size_is(n_gids)] 4905772Sas200622 * ulong gids[*]; // variable-length. 4915772Sas200622 * }; 4925772Sas200622 * 4935772Sas200622 * CONFORMANT constructs have a dynamic size in local memory and in the 4945772Sas200622 * PDU. The CONFORMANT quality is indicated by the [size_is()] advice. 4955772Sas200622 * CONFORMANT constructs have the following header: 4965772Sas200622 * 4975772Sas200622 * struct conformant_header { 4985772Sas200622 * ulong size_is; 4995772Sas200622 * }; 5005772Sas200622 * 5015772Sas200622 * (Multi-dimensional CONFORMANT arrays have a similar header for each 5025772Sas200622 * dimension - not implemented). 5035772Sas200622 * 5045772Sas200622 * Example CONFORMANT construct: 5055772Sas200622 * 5065772Sas200622 * struct user { 5075772Sas200622 * char * name; 5085772Sas200622 * struct credentials cred; // see above 5095772Sas200622 * }; 5105772Sas200622 * 5115772Sas200622 * Consider the data tree: 5125772Sas200622 * 5135772Sas200622 * +--------+ 5145772Sas200622 * | user | 5155772Sas200622 * +--------+ 5165772Sas200622 * | name ----> "fred" (the string is a different OUTER) 5175772Sas200622 * | uid | 5185772Sas200622 * | gid | 5195772Sas200622 * | n_gids | for example, 3 5205772Sas200622 * | gids[0]| 5215772Sas200622 * | gids[1]| 5225772Sas200622 * | gids[2]| 5235772Sas200622 * +--------+ 5245772Sas200622 * 5255772Sas200622 * The OUTER construct in the Stub Data would be: 5265772Sas200622 * 5275772Sas200622 * +---+---------+---------------------------------------------+ 5285772Sas200622 * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]| 5295772Sas200622 * +---+---------+---------------------------------------------+ 5305772Sas200622 * szing hdr|user |<-------------- user.cred ------------>| 5315772Sas200622 * |<--- fixed-size ---->|<----- conformant ---->| 5325772Sas200622 * 5335772Sas200622 * The ndr_typeinfo for struct user will have: 5345772Sas200622 * pdu_fixed_size_part = 16 four long words (name uid gid n_gids) 5355772Sas200622 * pdu_variable_size_part = 4 per element, sizeof gids[0] 5365772Sas200622 * 5375772Sas200622 * VARYING CONSTRUCTS -- NOT IMPLEMENTED 5385772Sas200622 * 5395772Sas200622 * VARYING constructs have the following header: 5405772Sas200622 * 5415772Sas200622 * struct varying_header { 5425772Sas200622 * ulong first_is; 5435772Sas200622 * ulong length_is; 5445772Sas200622 * }; 5455772Sas200622 * 5465772Sas200622 * This indicates which interval of an array is significant. 5475772Sas200622 * Non-intersecting elements of the array are undefined and usually 5485772Sas200622 * zero-filled. The first_is parameter for C arrays is always 0 for 5495772Sas200622 * the first element. 5505772Sas200622 * 5515772Sas200622 * N.B. Constructs may contain one CONFORMANT element, which is always 5525772Sas200622 * last, but may contain many VARYING elements, which can be anywhere. 5535772Sas200622 * 5545772Sas200622 * VARYING CONFORMANT constructs have the sizing headers arranged like 5555772Sas200622 * this: 5565772Sas200622 * 5575772Sas200622 * struct conformant_header all_conformant[N_CONFORMANT_DIM]; 5585772Sas200622 * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS]; 5595772Sas200622 * 5605772Sas200622 * The sizing header is immediately followed by the values for the 5615772Sas200622 * construct. Again, we don't support more than one dimension and 5625772Sas200622 * we don't support VARYING constructs at this time. 5635772Sas200622 * 5645772Sas200622 * A good example of a VARYING/CONFORMANT data structure is the UNIX 5655772Sas200622 * directory entry: 5665772Sas200622 * 5675772Sas200622 * struct dirent { 5685772Sas200622 * ushort reclen; 5695772Sas200622 * ushort namlen; 5705772Sas200622 * ulong inum; 5715772Sas200622 * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL 5725772Sas200622 * uchar name[*]; 5735772Sas200622 * }; 5745772Sas200622 * 5755772Sas200622 * 5765772Sas200622 * STRINGS ARE A SPECIAL CASE 5775772Sas200622 * 5785772Sas200622 * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures 5795772Sas200622 * for strings. This is a simple one-dimensional variable-length array, 5805772Sas200622 * typically with its last element all zeroes. We handle strings with the 5815772Sas200622 * header: 5825772Sas200622 * 5835772Sas200622 * struct string_header { 5845772Sas200622 * ulong size_is; 5855772Sas200622 * ulong first_is; // always 0 5865772Sas200622 * ulong length_is; // always same as size_is 5875772Sas200622 * }; 5885772Sas200622 * 5895772Sas200622 * If general support for VARYING and VARYING/CONFORMANT mechanisms is 5905772Sas200622 * implemented, we probably won't need the strings special case. 5915772Sas200622 */ 5925772Sas200622 int 5935772Sas200622 mlndr_outer(struct ndr_reference *outer_ref) 5945772Sas200622 { 5955772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 5965772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 5975772Sas200622 int is_varlen = ti->pdu_size_variable_part; 5985772Sas200622 int is_union = NDR_IS_UNION(ti); 5995772Sas200622 int is_string = NDR_IS_STRING(ti); 6005772Sas200622 int error = NDR_ERR_OUTER_PARAMS_BAD; 6015772Sas200622 int params; 6025772Sas200622 6035772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 6045772Sas200622 6055772Sas200622 NDR_TATTLE(outer_ref, "--OUTER--"); 6065772Sas200622 6075772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 6085772Sas200622 if (!mlndr_outer_align(outer_ref)) 6095772Sas200622 return (0); /* error already set */ 6105772Sas200622 6115772Sas200622 /* Regardless of what it is, this is where it starts */ 6125772Sas200622 outer_ref->pdu_offset = mlnds->pdu_scan_offset; 6135772Sas200622 6145772Sas200622 if (is_union) { 6155772Sas200622 error = NDR_ERR_OUTER_UNION_ILLEGAL; 6165772Sas200622 NDR_SET_ERROR(outer_ref, error); 6175772Sas200622 return (0); 6185772Sas200622 } 6195772Sas200622 6205772Sas200622 switch (params) { 6215772Sas200622 case NDR_F_NONE: 6225772Sas200622 if (is_string) 6235772Sas200622 return (mlndr_outer_string(outer_ref)); 6245772Sas200622 if (is_varlen) 6255772Sas200622 return (mlndr_outer_conformant_construct(outer_ref)); 6265772Sas200622 6275772Sas200622 return (mlndr_outer_fixed(outer_ref)); 6285772Sas200622 break; 6295772Sas200622 6305772Sas200622 case NDR_F_SIZE_IS: 6315772Sas200622 case NDR_F_DIMENSION_IS: 6325772Sas200622 if (is_varlen) { 6335772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 6345772Sas200622 break; 6355772Sas200622 } 6365772Sas200622 6375772Sas200622 if (params == NDR_F_SIZE_IS) 6385772Sas200622 return (mlndr_outer_conformant_array(outer_ref)); 6395772Sas200622 else 6405772Sas200622 return (mlndr_outer_fixed_array(outer_ref)); 6415772Sas200622 break; 6425772Sas200622 6435772Sas200622 default: 6445772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 6455772Sas200622 break; 6465772Sas200622 } 6475772Sas200622 6485772Sas200622 /* 6495772Sas200622 * If we get here, something is wrong. Most likely, 6505772Sas200622 * the params flags do not match. 6515772Sas200622 */ 6525772Sas200622 NDR_SET_ERROR(outer_ref, error); 6535772Sas200622 return (0); 6545772Sas200622 } 6555772Sas200622 6565772Sas200622 int 6575772Sas200622 mlndr_outer_fixed(struct ndr_reference *outer_ref) 6585772Sas200622 { 6595772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 6605772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 6615772Sas200622 struct ndr_reference myref; 6625772Sas200622 char *valp = NULL; 6635772Sas200622 int is_varlen = ti->pdu_size_variable_part; 6645772Sas200622 int is_union = NDR_IS_UNION(ti); 6655772Sas200622 int is_string = NDR_IS_STRING(ti); 6665772Sas200622 int rc; 6675772Sas200622 unsigned n_hdr; 6685772Sas200622 unsigned n_fixed; 6695772Sas200622 unsigned n_variable; 6705772Sas200622 unsigned n_alloc; 6715772Sas200622 unsigned n_pdu_total; 6725772Sas200622 int params; 6735772Sas200622 6745772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 6755772Sas200622 6765772Sas200622 assert(!is_varlen && !is_string && !is_union); 6775772Sas200622 assert(params == NDR_F_NONE); 6785772Sas200622 6795772Sas200622 /* no header for this */ 6805772Sas200622 n_hdr = 0; 6815772Sas200622 6825772Sas200622 /* fixed part -- exactly one of these */ 6835772Sas200622 n_fixed = ti->pdu_size_fixed_part; 6845772Sas200622 assert(n_fixed > 0); 6855772Sas200622 6865772Sas200622 /* variable part -- exactly none of these */ 6875772Sas200622 n_variable = 0; 6885772Sas200622 6895772Sas200622 /* sum them up to determine the PDU space required */ 6905772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 6915772Sas200622 6925772Sas200622 /* similar sum to determine how much local memory is required */ 6935772Sas200622 n_alloc = n_fixed + n_variable; 6945772Sas200622 6955772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 6965772Sas200622 if (!rc) 6975772Sas200622 return (rc); /* error already set */ 6985772Sas200622 6995772Sas200622 switch (mlnds->m_op) { 7005772Sas200622 case NDR_M_OP_MARSHALL: 7015772Sas200622 valp = outer_ref->datum; 7025772Sas200622 assert(valp); 7035772Sas200622 if (outer_ref->backptr) { 7045772Sas200622 assert(valp == *outer_ref->backptr); 7055772Sas200622 } 7065772Sas200622 break; 7075772Sas200622 7085772Sas200622 case NDR_M_OP_UNMARSHALL: 7095772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 7105772Sas200622 if (!valp) { 7115772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 7125772Sas200622 return (0); 7135772Sas200622 } 7145772Sas200622 if (outer_ref->backptr) 7155772Sas200622 *outer_ref->backptr = valp; 7165772Sas200622 outer_ref->datum = valp; 7175772Sas200622 break; 7185772Sas200622 7195772Sas200622 default: 7205772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 7215772Sas200622 return (0); 7225772Sas200622 } 7235772Sas200622 7245772Sas200622 bzero(&myref, sizeof (myref)); 7255772Sas200622 myref.stream = mlnds; 7265772Sas200622 myref.enclosing = outer_ref; 7275772Sas200622 myref.ti = outer_ref->ti; 7285772Sas200622 myref.datum = outer_ref->datum; 7295772Sas200622 myref.name = "FIXED-VALUE"; 7305772Sas200622 myref.outer_flags = NDR_F_NONE; 7315772Sas200622 myref.inner_flags = NDR_F_NONE; 7325772Sas200622 7335772Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 7345772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 7355772Sas200622 7365772Sas200622 rc = mlndr_inner(&myref); 7375772Sas200622 if (!rc) 7385772Sas200622 return (rc); /* error already set */ 7395772Sas200622 7405772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 7415772Sas200622 return (1); 7425772Sas200622 } 7435772Sas200622 7445772Sas200622 int 7455772Sas200622 mlndr_outer_fixed_array(struct ndr_reference *outer_ref) 7465772Sas200622 { 7475772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 7485772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 7495772Sas200622 struct ndr_reference myref; 7505772Sas200622 char *valp = NULL; 7515772Sas200622 int is_varlen = ti->pdu_size_variable_part; 7525772Sas200622 int is_union = NDR_IS_UNION(ti); 7535772Sas200622 int is_string = NDR_IS_STRING(ti); 7545772Sas200622 int rc; 7555772Sas200622 unsigned n_hdr; 7565772Sas200622 unsigned n_fixed; 7575772Sas200622 unsigned n_variable; 7585772Sas200622 unsigned n_alloc; 7595772Sas200622 unsigned n_pdu_total; 7605772Sas200622 int params; 7615772Sas200622 7625772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 7635772Sas200622 7645772Sas200622 assert(!is_varlen && !is_string && !is_union); 7655772Sas200622 assert(params == NDR_F_DIMENSION_IS); 7665772Sas200622 7675772Sas200622 /* no header for this */ 7685772Sas200622 n_hdr = 0; 7695772Sas200622 7705772Sas200622 /* fixed part -- exactly dimension_is of these */ 7715772Sas200622 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 7725772Sas200622 assert(n_fixed > 0); 7735772Sas200622 7745772Sas200622 /* variable part -- exactly none of these */ 7755772Sas200622 n_variable = 0; 7765772Sas200622 7775772Sas200622 /* sum them up to determine the PDU space required */ 7785772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 7795772Sas200622 7805772Sas200622 /* similar sum to determine how much local memory is required */ 7815772Sas200622 n_alloc = n_fixed + n_variable; 7825772Sas200622 7835772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 7845772Sas200622 if (!rc) 7855772Sas200622 return (rc); /* error already set */ 7865772Sas200622 7875772Sas200622 switch (mlnds->m_op) { 7885772Sas200622 case NDR_M_OP_MARSHALL: 7895772Sas200622 valp = outer_ref->datum; 7905772Sas200622 assert(valp); 7915772Sas200622 if (outer_ref->backptr) { 7925772Sas200622 assert(valp == *outer_ref->backptr); 7935772Sas200622 } 7945772Sas200622 break; 7955772Sas200622 7965772Sas200622 case NDR_M_OP_UNMARSHALL: 7975772Sas200622 valp = MLNDS_MALLOC(mlnds, 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)); 8135772Sas200622 myref.stream = mlnds; 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 8255772Sas200622 rc = mlndr_inner(&myref); 8265772Sas200622 if (!rc) 8275772Sas200622 return (rc); /* error already set */ 8285772Sas200622 8295772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 8305772Sas200622 return (1); 8315772Sas200622 } 8325772Sas200622 8335772Sas200622 int 8345772Sas200622 mlndr_outer_conformant_array(struct ndr_reference *outer_ref) 8355772Sas200622 { 8365772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 8375772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 8385772Sas200622 struct ndr_reference 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; 8505772Sas200622 int params; 8515772Sas200622 8525772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 8535772Sas200622 8545772Sas200622 assert(!is_varlen && !is_string && !is_union); 8555772Sas200622 assert(params == NDR_F_SIZE_IS); 8565772Sas200622 8575772Sas200622 /* conformant header for this */ 8585772Sas200622 n_hdr = 4; 8595772Sas200622 8605772Sas200622 /* fixed part -- exactly none of these */ 8615772Sas200622 n_fixed = 0; 8625772Sas200622 8635772Sas200622 /* variable part -- exactly size_of of these */ 8645772Sas200622 /* notice that it is the **fixed** size of the ti */ 8655772Sas200622 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 8665772Sas200622 8675772Sas200622 /* sum them up to determine the PDU space required */ 8685772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 8695772Sas200622 8705772Sas200622 /* similar sum to determine how much local memory is required */ 8715772Sas200622 n_alloc = n_fixed + n_variable; 8725772Sas200622 8735772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 8745772Sas200622 if (!rc) 8755772Sas200622 return (rc); /* error already set */ 8765772Sas200622 8775772Sas200622 switch (mlnds->m_op) { 8785772Sas200622 case NDR_M_OP_MARSHALL: 8795772Sas200622 size_is = outer_ref->size_is; 8805772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 8815772Sas200622 if (!rc) 8825772Sas200622 return (0); /* error already set */ 8835772Sas200622 8845772Sas200622 valp = outer_ref->datum; 8855772Sas200622 assert(valp); 8865772Sas200622 if (outer_ref->backptr) { 8875772Sas200622 assert(valp == *outer_ref->backptr); 8885772Sas200622 } 8895772Sas200622 break; 8905772Sas200622 8915772Sas200622 case NDR_M_OP_UNMARSHALL: 8925772Sas200622 rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is); 8935772Sas200622 if (!rc) 8945772Sas200622 return (0); /* error already set */ 8955772Sas200622 8965772Sas200622 if (size_is != outer_ref->size_is) { 8975772Sas200622 NDR_SET_ERROR(outer_ref, 8985772Sas200622 NDR_ERR_SIZE_IS_MISMATCH_PDU); 8995772Sas200622 return (0); 9005772Sas200622 } 9015772Sas200622 902*6771Sjb150015 if (size_is > 0) { 903*6771Sjb150015 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 904*6771Sjb150015 if (!valp) { 905*6771Sjb150015 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 906*6771Sjb150015 return (0); 907*6771Sjb150015 } 9085772Sas200622 } 909*6771Sjb150015 9105772Sas200622 if (outer_ref->backptr) 9115772Sas200622 *outer_ref->backptr = valp; 9125772Sas200622 outer_ref->datum = valp; 9135772Sas200622 break; 9145772Sas200622 9155772Sas200622 default: 9165772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 9175772Sas200622 return (0); 9185772Sas200622 } 9195772Sas200622 9205772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 9215772Sas200622 outer_ref->type_flags = NDR_F_NONE; 9225772Sas200622 outer_ref->inner_flags = NDR_F_NONE; 9235772Sas200622 924*6771Sjb150015 if (size_is > 0) { 925*6771Sjb150015 bzero(&myref, sizeof (myref)); 926*6771Sjb150015 myref.stream = mlnds; 927*6771Sjb150015 myref.enclosing = outer_ref; 928*6771Sjb150015 myref.ti = outer_ref->ti; 929*6771Sjb150015 myref.datum = outer_ref->datum; 930*6771Sjb150015 myref.name = "CONFORMANT-ARRAY"; 931*6771Sjb150015 myref.outer_flags = NDR_F_NONE; 932*6771Sjb150015 myref.inner_flags = NDR_F_SIZE_IS; 933*6771Sjb150015 myref.size_is = outer_ref->size_is; 934*6771Sjb150015 935*6771Sjb150015 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 936*6771Sjb150015 myref.dimension_is = outer_ref->size_is; /* convenient */ 937*6771Sjb150015 938*6771Sjb150015 myref.pdu_offset = outer_ref->pdu_offset + 4; 939*6771Sjb150015 940*6771Sjb150015 rc = mlndr_inner(&myref); 941*6771Sjb150015 if (!rc) 942*6771Sjb150015 return (rc); /* error already set */ 943*6771Sjb150015 } 9445772Sas200622 9455772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 9465772Sas200622 return (1); 9475772Sas200622 } 9485772Sas200622 9495772Sas200622 int 9505772Sas200622 mlndr_outer_conformant_construct(struct ndr_reference *outer_ref) 9515772Sas200622 { 9525772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 9535772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 9545772Sas200622 struct ndr_reference myref; 9555772Sas200622 char *valp = NULL; 9565772Sas200622 int is_varlen = ti->pdu_size_variable_part; 9575772Sas200622 int is_union = NDR_IS_UNION(ti); 9585772Sas200622 int is_string = NDR_IS_STRING(ti); 9595772Sas200622 unsigned long size_is; 9605772Sas200622 int rc; 9615772Sas200622 unsigned n_hdr; 9625772Sas200622 unsigned n_fixed; 9635772Sas200622 unsigned n_variable; 9645772Sas200622 unsigned n_alloc; 9655772Sas200622 unsigned n_pdu_total; 9665772Sas200622 int params; 9675772Sas200622 9685772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 9695772Sas200622 9705772Sas200622 assert(is_varlen && !is_string && !is_union); 9715772Sas200622 assert(params == NDR_F_NONE); 9725772Sas200622 9735772Sas200622 /* conformant header for this */ 9745772Sas200622 n_hdr = 4; 9755772Sas200622 9765772Sas200622 /* fixed part -- exactly one of these */ 9775772Sas200622 n_fixed = ti->pdu_size_fixed_part; 9785772Sas200622 9795772Sas200622 /* variable part -- exactly size_of of these */ 9805772Sas200622 n_variable = 0; /* 0 for the moment */ 9815772Sas200622 9825772Sas200622 /* sum them up to determine the PDU space required */ 9835772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 9845772Sas200622 9855772Sas200622 /* similar sum to determine how much local memory is required */ 9865772Sas200622 n_alloc = n_fixed + n_variable; 9875772Sas200622 9885772Sas200622 /* For the moment, grow enough for the fixed-size part */ 9895772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 9905772Sas200622 if (!rc) 9915772Sas200622 return (rc); /* error already set */ 9925772Sas200622 9935772Sas200622 switch (mlnds->m_op) { 9945772Sas200622 case NDR_M_OP_MARSHALL: 9955772Sas200622 /* 9965772Sas200622 * We don't know the size yet. We have to wait for 9975772Sas200622 * it. Proceed with the fixed-size part, and await 9985772Sas200622 * the call to mlndr_size_is(). 9995772Sas200622 */ 10005772Sas200622 size_is = 0; 10015772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 10025772Sas200622 if (!rc) 10035772Sas200622 return (0); /* error already set */ 10045772Sas200622 10055772Sas200622 valp = outer_ref->datum; 10065772Sas200622 assert(valp); 10075772Sas200622 if (outer_ref->backptr) { 10085772Sas200622 assert(valp == *outer_ref->backptr); 10095772Sas200622 } 10105772Sas200622 break; 10115772Sas200622 10125772Sas200622 case NDR_M_OP_UNMARSHALL: 10135772Sas200622 /* 10145772Sas200622 * We know the size of the variable part because 10155772Sas200622 * of the CONFORMANT header. We will verify 10165772Sas200622 * the header against the [size_is(X)] advice 10175772Sas200622 * later when mlndr_size_is() is called. 10185772Sas200622 */ 10195772Sas200622 rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is); 10205772Sas200622 if (!rc) 10215772Sas200622 return (0); /* error already set */ 10225772Sas200622 10235772Sas200622 /* recalculate metrics */ 10245772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 10255772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 10265772Sas200622 n_alloc = n_fixed + n_variable; 10275772Sas200622 10285772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 10295772Sas200622 if (!rc) 10305772Sas200622 return (rc); /* error already set */ 10315772Sas200622 10325772Sas200622 outer_ref->size_is = size_is; /* verified later */ 10335772Sas200622 10345772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 10355772Sas200622 if (!valp) { 10365772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 10375772Sas200622 return (0); 10385772Sas200622 } 10395772Sas200622 if (outer_ref->backptr) 10405772Sas200622 *outer_ref->backptr = valp; 10415772Sas200622 outer_ref->datum = valp; 10425772Sas200622 break; 10435772Sas200622 10445772Sas200622 default: 10455772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 10465772Sas200622 return (0); 10475772Sas200622 } 10485772Sas200622 1049*6771Sjb150015 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 1050*6771Sjb150015 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 1051*6771Sjb150015 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 1052*6771Sjb150015 10535772Sas200622 bzero(&myref, sizeof (myref)); 10545772Sas200622 myref.stream = mlnds; 10555772Sas200622 myref.enclosing = outer_ref; 10565772Sas200622 myref.ti = outer_ref->ti; 10575772Sas200622 myref.datum = outer_ref->datum; 10585772Sas200622 myref.name = "CONFORMANT-CONSTRUCT"; 10595772Sas200622 myref.outer_flags = NDR_F_NONE; 10605772Sas200622 myref.inner_flags = NDR_F_NONE; 10615772Sas200622 myref.size_is = outer_ref->size_is; 10625772Sas200622 10635772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4; 10645772Sas200622 10655772Sas200622 rc = mlndr_inner(&myref); 10665772Sas200622 if (!rc) 10675772Sas200622 return (rc); /* error already set */ 10685772Sas200622 10695772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 10705772Sas200622 10715772Sas200622 if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 10725772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 10735772Sas200622 return (0); 10745772Sas200622 } 10755772Sas200622 10765772Sas200622 return (1); 10775772Sas200622 } 10785772Sas200622 10795772Sas200622 int 10805772Sas200622 mlndr_size_is(struct ndr_reference *ref) 10815772Sas200622 { 10825772Sas200622 struct mlndr_stream *mlnds = ref->stream; 10835772Sas200622 struct ndr_reference *outer_ref = mlnds->outer_current; 10845772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 10855772Sas200622 unsigned long size_is; 10865772Sas200622 int rc; 10875772Sas200622 unsigned n_hdr; 10885772Sas200622 unsigned n_fixed; 10895772Sas200622 unsigned n_variable; 10905772Sas200622 unsigned n_pdu_total; 10915772Sas200622 10925772Sas200622 assert(ref->inner_flags & NDR_F_SIZE_IS); 10935772Sas200622 size_is = ref->size_is; 10945772Sas200622 10955772Sas200622 if (outer_ref->type_flags != NDR_F_SIZE_IS) { 10965772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 10975772Sas200622 return (0); 10985772Sas200622 } 10995772Sas200622 11005772Sas200622 if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 11015772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 11025772Sas200622 return (0); 11035772Sas200622 } 11045772Sas200622 11055772Sas200622 /* repeat metrics, see mlndr_conformant_construct() above */ 11065772Sas200622 n_hdr = 4; 11075772Sas200622 n_fixed = ti->pdu_size_fixed_part; 11085772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 11095772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 11105772Sas200622 11115772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 11125772Sas200622 if (!rc) 11135772Sas200622 return (rc); /* error already set */ 11145772Sas200622 11155772Sas200622 switch (mlnds->m_op) { 11165772Sas200622 case NDR_M_OP_MARSHALL: 11175772Sas200622 /* 11185772Sas200622 * We have to set the sizing header and extend 11195772Sas200622 * the size of the PDU (already done). 11205772Sas200622 */ 11215772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 11225772Sas200622 if (!rc) 11235772Sas200622 return (0); /* error already set */ 11245772Sas200622 break; 11255772Sas200622 11265772Sas200622 case NDR_M_OP_UNMARSHALL: 11275772Sas200622 /* 11285772Sas200622 * Allocation done during mlndr_conformant_construct(). 11295772Sas200622 * All we are doing here is verifying that the 11305772Sas200622 * intended size (ref->size_is) matches the sizing header. 11315772Sas200622 */ 11325772Sas200622 if (size_is != outer_ref->size_is) { 11335772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 11345772Sas200622 return (0); 11355772Sas200622 } 11365772Sas200622 break; 11375772Sas200622 11385772Sas200622 default: 11395772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 11405772Sas200622 return (0); 11415772Sas200622 } 11425772Sas200622 11435772Sas200622 outer_ref->inner_flags |= NDR_F_SIZE_IS; 11445772Sas200622 outer_ref->size_is = ref->size_is; 11455772Sas200622 return (1); 11465772Sas200622 } 11475772Sas200622 11485772Sas200622 int 11495772Sas200622 mlndr_outer_string(struct ndr_reference *outer_ref) 11505772Sas200622 { 11515772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 11525772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 11535772Sas200622 struct ndr_reference myref; 11545772Sas200622 char *valp = NULL; 11555772Sas200622 unsigned is_varlen = ti->pdu_size_variable_part; 11565772Sas200622 int is_union = NDR_IS_UNION(ti); 11575772Sas200622 int is_string = NDR_IS_STRING(ti); 11585772Sas200622 int rc; 11595772Sas200622 unsigned n_zeroes; 11605772Sas200622 unsigned ix; 11615772Sas200622 unsigned long size_is; 11625772Sas200622 unsigned long first_is; 11635772Sas200622 unsigned long length_is; 11645772Sas200622 unsigned n_hdr; 11655772Sas200622 unsigned n_fixed; 11665772Sas200622 unsigned n_variable; 11675772Sas200622 unsigned n_alloc; 11685772Sas200622 unsigned n_pdu_total; 11695772Sas200622 int params; 11705772Sas200622 11715772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 11725772Sas200622 11735772Sas200622 assert(is_varlen && is_string && !is_union); 11745772Sas200622 assert(params == NDR_F_NONE); 11755772Sas200622 11765772Sas200622 /* string header for this: size_is first_is length_is */ 11775772Sas200622 n_hdr = 12; 11785772Sas200622 11795772Sas200622 /* fixed part -- exactly none of these */ 11805772Sas200622 n_fixed = 0; 11815772Sas200622 11825772Sas200622 if (!mlndr_outer_grow(outer_ref, n_hdr)) 11835772Sas200622 return (0); /* error already set */ 11845772Sas200622 11855772Sas200622 switch (mlnds->m_op) { 11865772Sas200622 case NDR_M_OP_MARSHALL: 11875772Sas200622 valp = outer_ref->datum; 11885772Sas200622 assert(valp); 11895772Sas200622 11905772Sas200622 if (outer_ref->backptr) 11915772Sas200622 assert(valp == *outer_ref->backptr); 11925772Sas200622 11935772Sas200622 if (ti == &ndt_s_wchar) { 11945772Sas200622 /* 11955772Sas200622 * size_is is the number of characters in the string, 11965772Sas200622 * including the null. We assume valp is UTF-8 encoded. 11975772Sas200622 * We can use mts_wcequiv_strlen for ASCII, extended 11985772Sas200622 * ASCII or Unicode (UCS-2). 11995772Sas200622 */ 12005772Sas200622 size_is = (mts_wcequiv_strlen(valp) / 12015772Sas200622 sizeof (mts_wchar_t)) + 1; 12025772Sas200622 12035772Sas200622 if (size_is > NDR_STRING_MAX) { 12045772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 12055772Sas200622 return (0); 12065772Sas200622 } 12075772Sas200622 } else { 12085772Sas200622 valp = outer_ref->datum; 12095772Sas200622 n_zeroes = 0; 12105772Sas200622 for (ix = 0; ix < 1024; ix++) { 12115772Sas200622 if (valp[ix] == 0) { 12125772Sas200622 n_zeroes++; 12135772Sas200622 if (n_zeroes >= is_varlen && 12145772Sas200622 ix % is_varlen == 0) { 12155772Sas200622 break; 12165772Sas200622 } 12175772Sas200622 } else { 12185772Sas200622 n_zeroes = 0; 12195772Sas200622 } 12205772Sas200622 } 12215772Sas200622 if (ix >= 1024) { 12225772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 12235772Sas200622 return (0); 12245772Sas200622 } 12255772Sas200622 size_is = ix+1; 12265772Sas200622 } 12275772Sas200622 12285772Sas200622 first_is = 0; 12295772Sas200622 12305772Sas200622 if (mlnds->flags & MLNDS_F_NOTERM) 12315772Sas200622 length_is = size_is - 1; 12325772Sas200622 else 12335772Sas200622 length_is = size_is; 12345772Sas200622 12355772Sas200622 if (!mlndr_outer_poke_sizing(outer_ref, 0, &size_is) || 12365772Sas200622 !mlndr_outer_poke_sizing(outer_ref, 4, &first_is) || 12375772Sas200622 !mlndr_outer_poke_sizing(outer_ref, 8, &length_is)) 12385772Sas200622 return (0); /* error already set */ 12395772Sas200622 break; 12405772Sas200622 12415772Sas200622 case NDR_M_OP_UNMARSHALL: 12425772Sas200622 if (!mlndr_outer_peek_sizing(outer_ref, 0, &size_is) || 12435772Sas200622 !mlndr_outer_peek_sizing(outer_ref, 4, &first_is) || 12445772Sas200622 !mlndr_outer_peek_sizing(outer_ref, 8, &length_is)) 12455772Sas200622 return (0); /* error already set */ 12465772Sas200622 12475772Sas200622 /* 12485772Sas200622 * In addition to the first_is check, we used to check that 12495772Sas200622 * size_is or size_is-1 was equal to length_is but Windows95 12505772Sas200622 * doesn't conform to this "rule" (see variable part below). 12515772Sas200622 * The srvmgr tool for Windows95 sent the following values 12525772Sas200622 * for a path string: 12535772Sas200622 * 12545772Sas200622 * size_is = 261 (0x105) 12555772Sas200622 * first_is = 0 12565772Sas200622 * length_is = 53 (0x35) 12575772Sas200622 * 12585772Sas200622 * The length_is was correct (for the given path) but the 12595772Sas200622 * size_is was the maximum path length rather than being 12605772Sas200622 * related to length_is. 12615772Sas200622 */ 12625772Sas200622 if (first_is != 0) { 12635772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 12645772Sas200622 return (0); 12655772Sas200622 } 12665772Sas200622 12675772Sas200622 if (ti == &ndt_s_wchar) { 12685772Sas200622 /* 12695772Sas200622 * Decoding Unicode to UTF-8; we need to allow 12705772Sas200622 * for the maximum possible char size. It would 12715772Sas200622 * be nice to use mbequiv_strlen but the string 12725772Sas200622 * may not be null terminated. 12735772Sas200622 */ 12745772Sas200622 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX; 12755772Sas200622 } else { 12765772Sas200622 n_alloc = (size_is + 1) * is_varlen; 12775772Sas200622 } 12785772Sas200622 12795772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 12805772Sas200622 if (!valp) { 12815772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 12825772Sas200622 return (0); 12835772Sas200622 } 12845772Sas200622 12855772Sas200622 bzero(valp, (size_is+1) * is_varlen); 12865772Sas200622 12875772Sas200622 if (outer_ref->backptr) 12885772Sas200622 *outer_ref->backptr = valp; 12895772Sas200622 outer_ref->datum = valp; 12905772Sas200622 break; 12915772Sas200622 12925772Sas200622 default: 12935772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 12945772Sas200622 return (0); 12955772Sas200622 } 12965772Sas200622 12975772Sas200622 /* 12985772Sas200622 * Variable part - exactly length_is of these. 12995772Sas200622 * 13005772Sas200622 * Usually, length_is is same as size_is and includes nul. 13015772Sas200622 * Some protocols use length_is = size_is-1, and length_is does 13025772Sas200622 * not include the nul (which is more consistent with DCE spec). 13035772Sas200622 * If the length_is is 0, there is no data following the 13045772Sas200622 * sizing header, regardless of size_is. 13055772Sas200622 */ 13065772Sas200622 n_variable = length_is * is_varlen; 13075772Sas200622 13085772Sas200622 /* sum them up to determine the PDU space required */ 13095772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 13105772Sas200622 13115772Sas200622 /* similar sum to determine how much local memory is required */ 13125772Sas200622 n_alloc = n_fixed + n_variable; 13135772Sas200622 13145772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 13155772Sas200622 if (!rc) 13165772Sas200622 return (rc); /* error already set */ 13175772Sas200622 13185772Sas200622 if (length_is > 0) { 13195772Sas200622 bzero(&myref, sizeof (myref)); 13205772Sas200622 myref.stream = mlnds; 13215772Sas200622 myref.enclosing = outer_ref; 13225772Sas200622 myref.ti = outer_ref->ti; 13235772Sas200622 myref.datum = outer_ref->datum; 13245772Sas200622 myref.name = "OUTER-STRING"; 13255772Sas200622 myref.outer_flags = NDR_F_IS_STRING; 13265772Sas200622 myref.inner_flags = NDR_F_NONE; 13275772Sas200622 13285772Sas200622 /* 13295772Sas200622 * Set up size_is and strlen_is for mlndr_s_wchar. 13305772Sas200622 */ 13315772Sas200622 myref.size_is = size_is; 13325772Sas200622 myref.strlen_is = length_is; 13335772Sas200622 } 13345772Sas200622 13355772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 12; 13365772Sas200622 13375772Sas200622 /* 13385772Sas200622 * Don't try to decode empty strings. 13395772Sas200622 */ 13405772Sas200622 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 13415772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 13425772Sas200622 return (1); 13435772Sas200622 } 13445772Sas200622 13455772Sas200622 if ((size_is != 0) && (length_is != 0)) { 13465772Sas200622 rc = mlndr_inner(&myref); 13475772Sas200622 if (!rc) 13485772Sas200622 return (rc); /* error already set */ 13495772Sas200622 } 13505772Sas200622 13515772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 13525772Sas200622 return (1); 13535772Sas200622 } 13545772Sas200622 13555772Sas200622 int 13565772Sas200622 mlndr_outer_peek_sizing(struct ndr_reference *outer_ref, unsigned offset, 13575772Sas200622 unsigned long *sizing_p) 13585772Sas200622 { 13595772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 13605772Sas200622 unsigned long pdu_offset; 13615772Sas200622 int rc; 13625772Sas200622 13635772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 13645772Sas200622 13655772Sas200622 if (pdu_offset < mlnds->outer_current->pdu_offset || 13665772Sas200622 pdu_offset > mlnds->outer_current->pdu_end_offset || 13675772Sas200622 pdu_offset+4 > mlnds->outer_current->pdu_end_offset) { 13685772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 13695772Sas200622 return (0); 13705772Sas200622 } 13715772Sas200622 13725772Sas200622 switch (mlnds->m_op) { 13735772Sas200622 case NDR_M_OP_MARSHALL: 13745772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 13755772Sas200622 return (0); 13765772Sas200622 13775772Sas200622 case NDR_M_OP_UNMARSHALL: 13785772Sas200622 rc = MLNDS_GET_PDU(mlnds, pdu_offset, 4, (char *)sizing_p, 13795772Sas200622 mlnds->swap, outer_ref); 13805772Sas200622 break; 13815772Sas200622 13825772Sas200622 default: 13835772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 13845772Sas200622 return (0); 13855772Sas200622 } 13865772Sas200622 13875772Sas200622 return (rc); 13885772Sas200622 } 13895772Sas200622 13905772Sas200622 int 13915772Sas200622 mlndr_outer_poke_sizing(struct ndr_reference *outer_ref, unsigned offset, 13925772Sas200622 unsigned long *sizing_p) 13935772Sas200622 { 13945772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 13955772Sas200622 unsigned long pdu_offset; 13965772Sas200622 int rc; 13975772Sas200622 13985772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 13995772Sas200622 14005772Sas200622 if (pdu_offset < mlnds->outer_current->pdu_offset || 14015772Sas200622 pdu_offset > mlnds->outer_current->pdu_end_offset || 14025772Sas200622 pdu_offset+4 > mlnds->outer_current->pdu_end_offset) { 14035772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 14045772Sas200622 return (0); 14055772Sas200622 } 14065772Sas200622 14075772Sas200622 switch (mlnds->m_op) { 14085772Sas200622 case NDR_M_OP_MARSHALL: 14095772Sas200622 rc = MLNDS_PUT_PDU(mlnds, pdu_offset, 4, (char *)sizing_p, 14105772Sas200622 mlnds->swap, outer_ref); 14115772Sas200622 break; 14125772Sas200622 14135772Sas200622 case NDR_M_OP_UNMARSHALL: 14145772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 14155772Sas200622 return (0); 14165772Sas200622 14175772Sas200622 default: 14185772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 14195772Sas200622 return (0); 14205772Sas200622 } 14215772Sas200622 14225772Sas200622 return (rc); 14235772Sas200622 } 14245772Sas200622 14255772Sas200622 /* 14265772Sas200622 * All OUTER constructs begin on a mod4 (dword) boundary - except 14275772Sas200622 * for the ones that don't: some MSRPC calls appear to use word or 14285772Sas200622 * packed alignment. Strings appear to be dword aligned. 14295772Sas200622 */ 14305772Sas200622 int 14315772Sas200622 mlndr_outer_align(struct ndr_reference *outer_ref) 14325772Sas200622 { 14335772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 14345772Sas200622 int rc; 14355772Sas200622 unsigned n_pad; 14365772Sas200622 unsigned align; 14375772Sas200622 14385772Sas200622 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 14395772Sas200622 align = outer_ref->ti->alignment; 14405772Sas200622 n_pad = ((align + 1) - mlnds->pdu_scan_offset) & align; 14415772Sas200622 } else { 14425772Sas200622 n_pad = (4 - mlnds->pdu_scan_offset) & 3; 14435772Sas200622 } 14445772Sas200622 14455772Sas200622 if (n_pad == 0) 14465772Sas200622 return (1); /* already aligned, often the case */ 14475772Sas200622 14485772Sas200622 if (!mlndr_outer_grow(outer_ref, n_pad)) 14495772Sas200622 return (0); /* error already set */ 14505772Sas200622 14515772Sas200622 switch (mlnds->m_op) { 14525772Sas200622 case NDR_M_OP_MARSHALL: 14535772Sas200622 rc = MLNDS_PAD_PDU(mlnds, 14545772Sas200622 mlnds->pdu_scan_offset, n_pad, outer_ref); 14555772Sas200622 if (!rc) { 14565772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 14575772Sas200622 return (0); 14585772Sas200622 } 14595772Sas200622 break; 14605772Sas200622 14615772Sas200622 case NDR_M_OP_UNMARSHALL: 14625772Sas200622 break; 14635772Sas200622 14645772Sas200622 default: 14655772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 14665772Sas200622 return (0); 14675772Sas200622 } 14685772Sas200622 14695772Sas200622 mlnds->pdu_scan_offset += n_pad; 14705772Sas200622 return (1); 14715772Sas200622 } 14725772Sas200622 14735772Sas200622 int 14745772Sas200622 mlndr_outer_grow(struct ndr_reference *outer_ref, unsigned n_total) 14755772Sas200622 { 14765772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 14775772Sas200622 unsigned long pdu_want_size; 14785772Sas200622 int rc, is_ok = 0; 14795772Sas200622 14805772Sas200622 pdu_want_size = mlnds->pdu_scan_offset + n_total; 14815772Sas200622 14825772Sas200622 if (pdu_want_size <= mlnds->pdu_max_size) { 14835772Sas200622 is_ok = 1; 14845772Sas200622 } 14855772Sas200622 14865772Sas200622 switch (mlnds->m_op) { 14875772Sas200622 case NDR_M_OP_MARSHALL: 14885772Sas200622 if (is_ok) 14895772Sas200622 break; 14905772Sas200622 rc = MLNDS_GROW_PDU(mlnds, pdu_want_size, outer_ref); 14915772Sas200622 if (!rc) { 14925772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 14935772Sas200622 return (0); 14945772Sas200622 } 14955772Sas200622 break; 14965772Sas200622 14975772Sas200622 case NDR_M_OP_UNMARSHALL: 14985772Sas200622 if (is_ok) 14995772Sas200622 break; 15005772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 15015772Sas200622 return (0); 15025772Sas200622 15035772Sas200622 default: 15045772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 15055772Sas200622 return (0); 15065772Sas200622 } 15075772Sas200622 15085772Sas200622 if (mlnds->pdu_size < pdu_want_size) 15095772Sas200622 mlnds->pdu_size = pdu_want_size; 15105772Sas200622 15115772Sas200622 outer_ref->pdu_end_offset = pdu_want_size; 15125772Sas200622 return (1); 15135772Sas200622 } 15145772Sas200622 15155772Sas200622 /* 15165772Sas200622 * INNER ELEMENTS 15175772Sas200622 * 15185772Sas200622 * The local datum (arg_ref->datum) already exists, there is no need to 15195772Sas200622 * malloc() it. The datum should point at a member of a structure. 15205772Sas200622 * 15215772Sas200622 * For the most part, mlndr_inner() and its helpers are just a sanity 15225772Sas200622 * check. The underlying ti->ndr_func() could be called immediately 15235772Sas200622 * for non-pointer elements. For the sake of robustness, we detect 15245772Sas200622 * run-time errors here. Most of the situations this protects against 15255772Sas200622 * have already been checked by the IDL compiler. This is also a 15265772Sas200622 * common point for processing of all data, and so is a convenient 15275772Sas200622 * place to work from for debugging. 15285772Sas200622 */ 15295772Sas200622 int 15305772Sas200622 mlndr_inner(struct ndr_reference *arg_ref) 15315772Sas200622 { 15325772Sas200622 struct ndr_typeinfo *ti = arg_ref->ti; 15335772Sas200622 int is_varlen = ti->pdu_size_variable_part; 15345772Sas200622 int is_union = NDR_IS_UNION(ti); 15355772Sas200622 int error = NDR_ERR_INNER_PARAMS_BAD; 15365772Sas200622 int params; 15375772Sas200622 15385772Sas200622 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 15395772Sas200622 15405772Sas200622 switch (params) { 15415772Sas200622 case NDR_F_NONE: 15425772Sas200622 if (is_union) { 15435772Sas200622 error = NDR_ERR_SWITCH_VALUE_MISSING; 15445772Sas200622 break; 15455772Sas200622 } 15465772Sas200622 return (*ti->ndr_func)(arg_ref); 15475772Sas200622 break; 15485772Sas200622 15495772Sas200622 case NDR_F_SIZE_IS: 15505772Sas200622 case NDR_F_DIMENSION_IS: 15515772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 15525772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 15535772Sas200622 if (is_varlen) { 15545772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 15555772Sas200622 break; 15565772Sas200622 } 15575772Sas200622 if (is_union) { 15585772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15595772Sas200622 break; 15605772Sas200622 } 15615772Sas200622 if (params & NDR_F_IS_POINTER) 15625772Sas200622 return (mlndr_inner_pointer(arg_ref)); 15635772Sas200622 else if (params & NDR_F_IS_REFERENCE) 15645772Sas200622 return (mlndr_inner_reference(arg_ref)); 15655772Sas200622 else 15665772Sas200622 return (mlndr_inner_array(arg_ref)); 15675772Sas200622 break; 15685772Sas200622 15695772Sas200622 case NDR_F_IS_POINTER: /* type is pointer to one something */ 15705772Sas200622 if (is_union) { 15715772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15725772Sas200622 break; 15735772Sas200622 } 15745772Sas200622 return (mlndr_inner_pointer(arg_ref)); 15755772Sas200622 break; 15765772Sas200622 15775772Sas200622 case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 15785772Sas200622 if (is_union) { 15795772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 15805772Sas200622 break; 15815772Sas200622 } 15825772Sas200622 return (mlndr_inner_reference(arg_ref)); 15835772Sas200622 break; 15845772Sas200622 15855772Sas200622 case NDR_F_SWITCH_IS: 15865772Sas200622 if (!is_union) { 15875772Sas200622 error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 15885772Sas200622 break; 15895772Sas200622 } 15905772Sas200622 return (*ti->ndr_func)(arg_ref); 15915772Sas200622 break; 15925772Sas200622 15935772Sas200622 default: 15945772Sas200622 error = NDR_ERR_INNER_PARAMS_BAD; 15955772Sas200622 break; 15965772Sas200622 } 15975772Sas200622 15985772Sas200622 /* 15995772Sas200622 * If we get here, something is wrong. Most likely, 16005772Sas200622 * the params flags do not match 16015772Sas200622 */ 16025772Sas200622 NDR_SET_ERROR(arg_ref, error); 16035772Sas200622 return (0); 16045772Sas200622 } 16055772Sas200622 16065772Sas200622 int 16075772Sas200622 mlndr_inner_pointer(struct ndr_reference *arg_ref) 16085772Sas200622 { 16095772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 16105772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16115772Sas200622 char **valpp = (char **)arg_ref->datum; 16125772Sas200622 struct ndr_reference *outer_ref; 16135772Sas200622 16145772Sas200622 if (!mlndr__ulong(arg_ref)) 16155772Sas200622 return (0); /* error */ 16165772Sas200622 if (!*valpp) 16175772Sas200622 return (1); /* NULL pointer */ 16185772Sas200622 16195772Sas200622 outer_ref = mlndr_enter_outer_queue(arg_ref); 16205772Sas200622 if (!outer_ref) 16215772Sas200622 return (0); /* error already set */ 16225772Sas200622 16235772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 16245772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 16255772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 16265772Sas200622 #ifdef NDR_INNER_NOT_YET 16275772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 16285772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 16295772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 16305772Sas200622 } 16315772Sas200622 #endif /* NDR_INNER_NOT_YET */ 16325772Sas200622 16335772Sas200622 outer_ref->backptr = valpp; 16345772Sas200622 16355772Sas200622 switch (mlnds->m_op) { 16365772Sas200622 case NDR_M_OP_MARSHALL: 16375772Sas200622 outer_ref->datum = *valpp; 16385772Sas200622 break; 16395772Sas200622 16405772Sas200622 case NDR_M_OP_UNMARSHALL: 16415772Sas200622 /* 16425772Sas200622 * This is probably wrong if the application allocated 16435772Sas200622 * memory in advance. Indicate no value for now. 16445772Sas200622 * ONC RPC handles this case. 16455772Sas200622 */ 16465772Sas200622 *valpp = 0; 16475772Sas200622 outer_ref->datum = 0; 16485772Sas200622 break; 16495772Sas200622 } 16505772Sas200622 16515772Sas200622 return (1); /* pointer dereference scheduled */ 16525772Sas200622 } 16535772Sas200622 16545772Sas200622 int 16555772Sas200622 mlndr_inner_reference(struct ndr_reference *arg_ref) 16565772Sas200622 { 16575772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 16585772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16595772Sas200622 char **valpp = (char **)arg_ref->datum; 16605772Sas200622 struct ndr_reference *outer_ref; 16615772Sas200622 16625772Sas200622 outer_ref = mlndr_enter_outer_queue(arg_ref); 16635772Sas200622 if (!outer_ref) 16645772Sas200622 return (0); /* error already set */ 16655772Sas200622 16665772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 16675772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 16685772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 16695772Sas200622 #ifdef NDR_INNER_REF_NOT_YET 16705772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 16715772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 16725772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 16735772Sas200622 } 16745772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */ 16755772Sas200622 16765772Sas200622 outer_ref->backptr = valpp; 16775772Sas200622 16785772Sas200622 switch (mlnds->m_op) { 16795772Sas200622 case NDR_M_OP_MARSHALL: 16805772Sas200622 outer_ref->datum = *valpp; 16815772Sas200622 break; 16825772Sas200622 16835772Sas200622 case NDR_M_OP_UNMARSHALL: 16845772Sas200622 /* 16855772Sas200622 * This is probably wrong if the application allocated 16865772Sas200622 * memory in advance. Indicate no value for now. 16875772Sas200622 * ONC RPC handles this case. 16885772Sas200622 */ 16895772Sas200622 *valpp = 0; 16905772Sas200622 outer_ref->datum = 0; 16915772Sas200622 break; 16925772Sas200622 } 16935772Sas200622 16945772Sas200622 return (1); /* pointer dereference scheduled */ 16955772Sas200622 } 16965772Sas200622 16975772Sas200622 int 16985772Sas200622 mlndr_inner_array(struct ndr_reference *encl_ref) 16995772Sas200622 { 17005772Sas200622 struct ndr_typeinfo *ti = encl_ref->ti; 17015772Sas200622 struct ndr_reference myref; 17025772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 17035772Sas200622 unsigned long n_elem; 17045772Sas200622 unsigned long i; 17055772Sas200622 char name[30]; 17065772Sas200622 17075772Sas200622 if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 17085772Sas200622 /* now is the time to check/set size */ 17095772Sas200622 if (!mlndr_size_is(encl_ref)) 17105772Sas200622 return (0); /* error already set */ 17115772Sas200622 n_elem = encl_ref->size_is; 17125772Sas200622 } else { 17135772Sas200622 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 17145772Sas200622 n_elem = encl_ref->dimension_is; 17155772Sas200622 } 17165772Sas200622 17175772Sas200622 bzero(&myref, sizeof (myref)); 17185772Sas200622 myref.enclosing = encl_ref; 17195772Sas200622 myref.stream = encl_ref->stream; 17205772Sas200622 myref.packed_alignment = 0; 17215772Sas200622 myref.ti = ti; 17225772Sas200622 myref.inner_flags = NDR_F_NONE; 17235772Sas200622 17245772Sas200622 for (i = 0; i < n_elem; i++) { 17255772Sas200622 (void) sprintf(name, "[%lu]", i); 17265772Sas200622 myref.name = name; 17275772Sas200622 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 17285772Sas200622 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 17295772Sas200622 17305772Sas200622 if (!mlndr_inner(&myref)) 17315772Sas200622 return (0); 17325772Sas200622 } 17335772Sas200622 17345772Sas200622 return (1); 17355772Sas200622 } 17365772Sas200622 17375772Sas200622 17385772Sas200622 /* 17395772Sas200622 * BASIC TYPES 17405772Sas200622 */ 17415772Sas200622 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17425772Sas200622 extern int mlndr_##TYPE(struct ndr_reference *encl_ref); \ 17435772Sas200622 struct ndr_typeinfo ndt_##TYPE = { \ 17445772Sas200622 1, /* NDR version */ \ 17455772Sas200622 (SIZE)-1, /* alignment */ \ 17465772Sas200622 NDR_F_NONE, /* flags */ \ 17475772Sas200622 mlndr_##TYPE, /* ndr_func */ \ 17485772Sas200622 SIZE, /* pdu_size_fixed_part */ \ 17495772Sas200622 0, /* pdu_size_variable_part */ \ 17505772Sas200622 SIZE, /* c_size_fixed_part */ \ 17515772Sas200622 0, /* c_size_variable_part */ \ 17525772Sas200622 }; \ 17535772Sas200622 int mlndr_##TYPE(struct ndr_reference *ref) { \ 17545772Sas200622 return (mlndr_basic_integer(ref, SIZE)); \ 17555772Sas200622 } 17565772Sas200622 17575772Sas200622 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 17585772Sas200622 extern int mlndr_s##TYPE(struct ndr_reference *encl_ref); \ 17595772Sas200622 struct ndr_typeinfo ndt_s##TYPE = { \ 17605772Sas200622 1, /* NDR version */ \ 17615772Sas200622 (SIZE)-1, /* alignment */ \ 17625772Sas200622 NDR_F_STRING, /* flags */ \ 17635772Sas200622 mlndr_s##TYPE, /* ndr_func */ \ 17645772Sas200622 0, /* pdu_size_fixed_part */ \ 17655772Sas200622 SIZE, /* pdu_size_variable_part */ \ 17665772Sas200622 0, /* c_size_fixed_part */ \ 17675772Sas200622 SIZE, /* c_size_variable_part */ \ 17685772Sas200622 }; \ 17695772Sas200622 int mlndr_s##TYPE(struct ndr_reference *ref) { \ 17705772Sas200622 return (mlndr_string_basic_integer(ref, &ndt_##TYPE)); \ 17715772Sas200622 } 17725772Sas200622 17735772Sas200622 #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 17745772Sas200622 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17755772Sas200622 MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 17765772Sas200622 17775772Sas200622 extern int 17785772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size); 17795772Sas200622 17805772Sas200622 extern int 17815772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref, 17825772Sas200622 struct ndr_typeinfo *type_under); 17835772Sas200622 17845772Sas200622 17855772Sas200622 MAKE_BASIC_TYPE(_char, 1) 17865772Sas200622 MAKE_BASIC_TYPE(_uchar, 1) 17875772Sas200622 MAKE_BASIC_TYPE(_short, 2) 17885772Sas200622 MAKE_BASIC_TYPE(_ushort, 2) 17895772Sas200622 MAKE_BASIC_TYPE(_long, 4) 17905772Sas200622 MAKE_BASIC_TYPE(_ulong, 4) 17915772Sas200622 17925772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2) 17935772Sas200622 17945772Sas200622 int 17955772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size) 17965772Sas200622 { 17975772Sas200622 struct mlndr_stream *mlnds = ref->stream; 17985772Sas200622 char *valp = (char *)ref->datum; 17995772Sas200622 int rc; 18005772Sas200622 18015772Sas200622 switch (mlnds->m_op) { 18025772Sas200622 case NDR_M_OP_MARSHALL: 18035772Sas200622 rc = MLNDS_PUT_PDU(mlnds, ref->pdu_offset, size, 18045772Sas200622 valp, mlnds->swap, ref); 18055772Sas200622 break; 18065772Sas200622 18075772Sas200622 case NDR_M_OP_UNMARSHALL: 18085772Sas200622 rc = MLNDS_GET_PDU(mlnds, ref->pdu_offset, size, 18095772Sas200622 valp, mlnds->swap, ref); 18105772Sas200622 break; 18115772Sas200622 18125772Sas200622 default: 18135772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 18145772Sas200622 return (0); 18155772Sas200622 } 18165772Sas200622 18175772Sas200622 return (rc); 18185772Sas200622 } 18195772Sas200622 18205772Sas200622 int 18215772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref, 18225772Sas200622 struct ndr_typeinfo *type_under) 18235772Sas200622 { 18245772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 18255772Sas200622 unsigned size = type_under->pdu_size_fixed_part; 18265772Sas200622 char *valp; 18275772Sas200622 struct ndr_reference myref; 18285772Sas200622 unsigned long i; 18295772Sas200622 long sense = 0; 18305772Sas200622 char name[30]; 18315772Sas200622 18325772Sas200622 assert(size != 0); 18335772Sas200622 18345772Sas200622 bzero(&myref, sizeof (myref)); 18355772Sas200622 myref.enclosing = encl_ref; 18365772Sas200622 myref.stream = encl_ref->stream; 18375772Sas200622 myref.packed_alignment = 0; 18385772Sas200622 myref.ti = type_under; 18395772Sas200622 myref.inner_flags = NDR_F_NONE; 18405772Sas200622 myref.name = name; 18415772Sas200622 18425772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 18435772Sas200622 (void) sprintf(name, "[%lu]", i); 18445772Sas200622 myref.pdu_offset = pdu_offset + i * size; 18455772Sas200622 valp = encl_ref->datum + i * size; 18465772Sas200622 myref.datum = valp; 18475772Sas200622 18485772Sas200622 if (!mlndr_inner(&myref)) 18495772Sas200622 return (0); 18505772Sas200622 18515772Sas200622 switch (size) { 18525772Sas200622 case 1: sense = *valp; break; 18535772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 18545772Sas200622 case 2: sense = *(short *)valp; break; 18555772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 18565772Sas200622 case 4: sense = *(long *)valp; break; 18575772Sas200622 } 18585772Sas200622 18595772Sas200622 if (!sense) 18605772Sas200622 break; 18615772Sas200622 } 18625772Sas200622 18635772Sas200622 return (1); 18645772Sas200622 } 18655772Sas200622 18665772Sas200622 18675772Sas200622 extern int mlndr_s_wchar(struct ndr_reference *encl_ref); 18685772Sas200622 struct ndr_typeinfo ndt_s_wchar = { 18695772Sas200622 1, /* NDR version */ 18705772Sas200622 2-1, /* alignment */ 18715772Sas200622 NDR_F_STRING, /* flags */ 18725772Sas200622 mlndr_s_wchar, /* ndr_func */ 18735772Sas200622 0, /* pdu_size_fixed_part */ 18745772Sas200622 2, /* pdu_size_variable_part */ 18755772Sas200622 0, /* c_size_fixed_part */ 18765772Sas200622 1, /* c_size_variable_part */ 18775772Sas200622 }; 18785772Sas200622 18795772Sas200622 18805772Sas200622 /* 18815772Sas200622 * Hand coded wchar function because all strings are transported 18825772Sas200622 * as wide characters. During NDR_M_OP_MARSHALL, we convert from 18835772Sas200622 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 18845772Sas200622 * convert from wide characters to multi-byte. 18855772Sas200622 * 18865772Sas200622 * It appeared that NT would sometimes leave a spurious character 18875772Sas200622 * in the data stream before the null wide_char, which would get 18885772Sas200622 * included in the string decode because we processed until the 18895772Sas200622 * null character. It now looks like NT does not always terminate 18905772Sas200622 * RPC Unicode strings and the terminating null is a side effect 18915772Sas200622 * of field alignment. So now we rely on the strlen_is (set up in 18925772Sas200622 * mlndr_outer_string) of the enclosing reference. This may or may 18935772Sas200622 * not include the null but it doesn't matter, the algorithm will 18945772Sas200622 * get it right. 18955772Sas200622 */ 18965772Sas200622 int 18975772Sas200622 mlndr_s_wchar(struct ndr_reference *encl_ref) 18985772Sas200622 { 18995772Sas200622 struct mlndr_stream *mlnds = encl_ref->stream; 19005772Sas200622 unsigned short wide_char; 19015772Sas200622 char *valp; 19025772Sas200622 struct ndr_reference myref; 19035772Sas200622 unsigned long i; 19045772Sas200622 char name[30]; 19055772Sas200622 int count; 19065772Sas200622 int char_count = 0; 19075772Sas200622 19085772Sas200622 if (mlnds->m_op == NDR_M_OP_UNMARSHALL) { 19095772Sas200622 /* 19105772Sas200622 * To avoid problems with zero length strings 19115772Sas200622 * we can just null terminate here and be done. 19125772Sas200622 */ 19135772Sas200622 if (encl_ref->strlen_is == 0) { 19145772Sas200622 encl_ref->datum[0] = '\0'; 19155772Sas200622 return (1); 19165772Sas200622 } 19175772Sas200622 } 19185772Sas200622 19195772Sas200622 bzero(&myref, sizeof (myref)); 19205772Sas200622 myref.enclosing = encl_ref; 19215772Sas200622 myref.stream = encl_ref->stream; 19225772Sas200622 myref.packed_alignment = 0; 19235772Sas200622 myref.ti = &ndt__wchar; 19245772Sas200622 myref.inner_flags = NDR_F_NONE; 19255772Sas200622 myref.datum = (char *)&wide_char; 19265772Sas200622 myref.name = name; 19275772Sas200622 myref.pdu_offset = encl_ref->pdu_offset; 19285772Sas200622 19295772Sas200622 valp = encl_ref->datum; 19305772Sas200622 count = 0; 19315772Sas200622 19325772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 19335772Sas200622 (void) sprintf(name, "[%lu]", i); 19345772Sas200622 19355772Sas200622 if (mlnds->m_op == NDR_M_OP_MARSHALL) { 19365772Sas200622 count = mts_mbtowc((mts_wchar_t *)&wide_char, valp, 19375772Sas200622 MTS_MB_CHAR_MAX); 19385772Sas200622 if (count < 0) { 19395772Sas200622 return (0); 19405772Sas200622 } else if (count == 0) { 19415772Sas200622 if (encl_ref->strlen_is != encl_ref->size_is) 19425772Sas200622 break; 19435772Sas200622 19445772Sas200622 /* 19455772Sas200622 * If the input char is 0, mbtowc 19465772Sas200622 * returns 0 without setting wide_char. 19475772Sas200622 * Set wide_char to 0 and a count of 1. 19485772Sas200622 */ 19495772Sas200622 wide_char = *valp; 19505772Sas200622 count = 1; 19515772Sas200622 } 19525772Sas200622 } 19535772Sas200622 19545772Sas200622 if (!mlndr_inner(&myref)) 19555772Sas200622 return (0); 19565772Sas200622 19575772Sas200622 if (mlnds->m_op == NDR_M_OP_UNMARSHALL) { 19585772Sas200622 count = mts_wctomb(valp, wide_char); 19595772Sas200622 19605772Sas200622 if ((++char_count) == encl_ref->strlen_is) { 19615772Sas200622 valp += count; 19625772Sas200622 *valp = '\0'; 19635772Sas200622 break; 19645772Sas200622 } 19655772Sas200622 } 19665772Sas200622 19675772Sas200622 if (!wide_char) 19685772Sas200622 break; 19695772Sas200622 19705772Sas200622 myref.pdu_offset += sizeof (wide_char); 19715772Sas200622 valp += count; 19725772Sas200622 } 19735772Sas200622 19745772Sas200622 return (1); 19755772Sas200622 } 19765772Sas200622 19775772Sas200622 /* 19785772Sas200622 * Converts a multibyte character string to a little-endian, wide-char 19795772Sas200622 * string. No more than nwchars wide characters are stored. 19805772Sas200622 * A terminating null wide character is appended if there is room. 19815772Sas200622 * 19825772Sas200622 * Returns the number of wide characters converted, not counting 19835772Sas200622 * any terminating null wide character. Returns -1 if an invalid 19845772Sas200622 * multibyte character is encountered. 19855772Sas200622 */ 19865772Sas200622 size_t 19875772Sas200622 ndr_mbstowcs(struct mlndr_stream *mlnds, mts_wchar_t *wcs, const char *mbs, 19885772Sas200622 size_t nwchars) 19895772Sas200622 { 19905772Sas200622 mts_wchar_t *start = wcs; 19915772Sas200622 int nbytes; 19925772Sas200622 19935772Sas200622 while (nwchars--) { 19945772Sas200622 nbytes = ndr_mbtowc(mlnds, wcs, mbs, MTS_MB_CHAR_MAX); 19955772Sas200622 if (nbytes < 0) { 19965772Sas200622 *wcs = 0; 19975772Sas200622 return ((size_t)-1); 19985772Sas200622 } 19995772Sas200622 20005772Sas200622 if (*mbs == 0) 20015772Sas200622 break; 20025772Sas200622 20035772Sas200622 ++wcs; 20045772Sas200622 mbs += nbytes; 20055772Sas200622 } 20065772Sas200622 20075772Sas200622 return (wcs - start); 20085772Sas200622 } 20095772Sas200622 20105772Sas200622 /* 20115772Sas200622 * Converts a multibyte character to a little-endian, wide-char, which 20125772Sas200622 * is stored in wcharp. Up to nbytes bytes are examined. 20135772Sas200622 * 20145772Sas200622 * If mbchar is valid, returns the number of bytes processed in mbchar. 20155772Sas200622 * If mbchar is invalid, returns -1. See also mts_mbtowc(). 20165772Sas200622 */ 20175772Sas200622 /*ARGSUSED*/ 20185772Sas200622 int 20195772Sas200622 ndr_mbtowc(struct mlndr_stream *mlnds, mts_wchar_t *wcharp, 20205772Sas200622 const char *mbchar, size_t nbytes) 20215772Sas200622 { 20225772Sas200622 int rc; 20235772Sas200622 20245772Sas200622 if ((rc = mts_mbtowc(wcharp, mbchar, nbytes)) < 0) 20255772Sas200622 return (rc); 20265772Sas200622 20275772Sas200622 #ifdef _BIG_ENDIAN 20285772Sas200622 if (mlnds == NULL || NDR_MODE_MATCH(mlnds, NDR_MODE_RETURN_SEND)) 20295772Sas200622 *wcharp = BSWAP_16(*wcharp); 20305772Sas200622 #endif 20315772Sas200622 20325772Sas200622 return (rc); 20335772Sas200622 } 2034