1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22f96bd5c8SAlan Wright * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 2433f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 25*d1855c81SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 26da6c28aaSamw */ 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * Network Data Representation (NDR) is a compatible subset of the DCE RPC 30da6c28aaSamw * and MSRPC NDR. NDR is used to move parameters consisting of 31da6c28aaSamw * complicated trees of data constructs between an RPC client and server. 32da6c28aaSamw */ 33da6c28aaSamw 3455bf511dSas #include <sys/byteorder.h> 35da6c28aaSamw #include <strings.h> 36da6c28aaSamw #include <assert.h> 37da6c28aaSamw #include <string.h> 383299f39fSGordon Ross #include <stdio.h> 39da6c28aaSamw #include <stdlib.h> 40da6c28aaSamw 413299f39fSGordon Ross #include <libmlrpc.h> 423299f39fSGordon Ross #include <ndr_wchar.h> 43da6c28aaSamw 44da6c28aaSamw #define NDR_IS_UNION(T) \ 45da6c28aaSamw (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION) 46da6c28aaSamw #define NDR_IS_STRING(T) \ 47da6c28aaSamw (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING) 48da6c28aaSamw 498d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar; 50da6c28aaSamw 51da6c28aaSamw /* 52da6c28aaSamw * The following synopsis describes the terms TOP-MOST, OUTER and INNER. 53da6c28aaSamw * 54da6c28aaSamw * Each parameter (call arguments and return values) is a TOP-MOST item. 55da6c28aaSamw * A TOP-MOST item consists of one or more OUTER items. An OUTER item 56da6c28aaSamw * consists of one or more INNER items. There are important differences 57da6c28aaSamw * between each kind, which, primarily, have to do with the allocation 58da6c28aaSamw * of memory to contain data structures and the order of processing. 59da6c28aaSamw * 60da6c28aaSamw * This is most easily demonstrated with a short example. 61da6c28aaSamw * Consider these structures: 62da6c28aaSamw * 63da6c28aaSamw * struct top_param { 64da6c28aaSamw * long level; 65da6c28aaSamw * struct list * head; 66da6c28aaSamw * long count; 67da6c28aaSamw * }; 68da6c28aaSamw * 69da6c28aaSamw * struct list { 70da6c28aaSamw * struct list * next; 71da6c28aaSamw * char * str; // a string 72da6c28aaSamw * }; 73da6c28aaSamw * 74da6c28aaSamw * Now, consider an instance tree like this: 75da6c28aaSamw * 76da6c28aaSamw * +---------+ +-------+ +-------+ 77da6c28aaSamw * |top_param| +--->|list #1| +--->|list #2| 78da6c28aaSamw * +---------+ | +-------+ | +-------+ 79da6c28aaSamw * | level | | | next ----+ | next --->(NULL) 80da6c28aaSamw * | head ----+ | str -->"foo" | str -->"bar" 81da6c28aaSamw * | count | | flag | | flag | 82da6c28aaSamw * +---------+ +-------+ +-------+ 83da6c28aaSamw * 84da6c28aaSamw * The DCE(MS)/RPC Stub Data encoding for the tree is the following. 85da6c28aaSamw * The vertical bars (|) indicate OUTER construct boundaries. 86da6c28aaSamw * 87da6c28aaSamw * +-----+----------------------+----------------------+-----+-----+-----+ 88da6c28aaSamw * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count| 89da6c28aaSamw * +-----+----------------------+----------------------+-----+-----+-----+ 90da6c28aaSamw * level |<----------------------- head -------------------------->|count 91da6c28aaSamw * TOP TOP TOP 92da6c28aaSamw * 93da6c28aaSamw * Here's what to notice: 94da6c28aaSamw * 95da6c28aaSamw * - The members of the TOP-MOST construct are scattered through the Stub 96da6c28aaSamw * Data in the order they occur. This example shows a TOP-MOST construct 97da6c28aaSamw * consisting of atomic types (pointers and integers). A construct 98da6c28aaSamw * (struct) within the TOP-MOST construct would be contiguous and not 99da6c28aaSamw * scattered. 100da6c28aaSamw * 101da6c28aaSamw * - The members of OUTER constructs are contiguous, which allows for 102da6c28aaSamw * non-copied relocated (fixed-up) data structures at the packet's 103da6c28aaSamw * destination. We don't do fix-ups here. The pointers within the 104da6c28aaSamw * OUTER constructs are processed depth-first in the order that they 105da6c28aaSamw * occur. If they were processed breadth first, the sequence would 106da6c28aaSamw * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may 107da6c28aaSamw * be variable length, and pointers are often encountered before the 108da6c28aaSamw * size(s) is known. 109da6c28aaSamw * 110da6c28aaSamw * - The INNER constructs are simply the members of an OUTER construct. 111da6c28aaSamw * 112da6c28aaSamw * For comparison, consider how ONC RPC would handle the same tree of 113da6c28aaSamw * data. ONC requires very little buffering, while DCE requires enough 114da6c28aaSamw * buffer space for the entire message. ONC does atom-by-atom depth-first 115da6c28aaSamw * (de)serialization and copy, while DCE allows for constructs to be 116da6c28aaSamw * "fixed-up" (relocated) in place at the destination. The packet data 117da6c28aaSamw * for the same tree processed by ONC RPC would look like this: 118da6c28aaSamw * 119da6c28aaSamw * +---------------------------------------------------------------------+ 120da6c28aaSamw * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count| 121da6c28aaSamw * +---------------------------------------------------------------------+ 122da6c28aaSamw * TOP #1 #2 #2 bar #2 #1 foo #1 TOP 123da6c28aaSamw * 124da6c28aaSamw * More details about each TOP-MOST, OUTER, and INNER constructs appear 125da6c28aaSamw * throughout this source file near where such constructs are processed. 126da6c28aaSamw * 127da6c28aaSamw * NDR_REFERENCE 128da6c28aaSamw * 1298d7e4166Sjose borrego * The primary object for NDR is the ndr_ref_t. 130da6c28aaSamw * 1318d7e4166Sjose borrego * An ndr reference indicates the local datum (i.e. native "C" data 132da6c28aaSamw * format), and the element within the Stub Data (contained within the 1338d7e4166Sjose borrego * RPC PDU (protocol data unit). An ndr reference also indicates, 134da6c28aaSamw * largely as a debugging aid, something about the type of the 135da6c28aaSamw * element/datum, and the enclosing construct for the element. The 1368d7e4166Sjose borrego * ndr reference's are typically allocated on the stack as locals, 1378d7e4166Sjose borrego * and the chain of ndr-reference.enclosing references is in reverse 138da6c28aaSamw * order of the call graph. 139da6c28aaSamw * 1408d7e4166Sjose borrego * The ndr-reference.datum is a pointer to the local memory that 1418d7e4166Sjose borrego * contains/receives the value. The ndr-reference.pdu_offset indicates 142da6c28aaSamw * where in the Stub Data the value is to be stored/retrieved. 143da6c28aaSamw * 1448d7e4166Sjose borrego * The ndr-reference also contains various parameters to the NDR 1458d7e4166Sjose borrego * process, such as ndr-reference.size_is, which indicates the size 1468d7e4166Sjose borrego * of variable length data, or ndr-reference.switch_is, which 147da6c28aaSamw * indicates the arm of a union to use. 148da6c28aaSamw * 149da6c28aaSamw * QUEUE OF OUTER REFERENCES 150da6c28aaSamw * 151da6c28aaSamw * Some OUTER constructs are variable size. Sometimes (often) we don't 152da6c28aaSamw * know the size of the OUTER construct until after pointers have been 153da6c28aaSamw * encountered. Hence, we can not begin processing the referent of the 154da6c28aaSamw * pointer until after the referring OUTER construct is completely 155da6c28aaSamw * processed, i.e. we don't know where to find/put the referent in the 156da6c28aaSamw * Stub Data until we know the size of all its predecessors. 157da6c28aaSamw * 158da6c28aaSamw * This is managed using the queue of OUTER references. The queue is 1598d7e4166Sjose borrego * anchored in ndr_stream.outer_queue_head. At any time, 1608d7e4166Sjose borrego * ndr_stream.outer_queue_tailp indicates where to put the 1618d7e4166Sjose borrego * ndr-reference for the next encountered pointer. 162da6c28aaSamw * 163da6c28aaSamw * Refer to the example above as we illustrate the queue here. In these 164da6c28aaSamw * illustrations, the queue entries are not the data structures themselves. 1658d7e4166Sjose borrego * Rather, they are ndr-reference entries which **refer** to the data 166da6c28aaSamw * structures in both the PDU and local memory. 167da6c28aaSamw * 168da6c28aaSamw * During some point in the processing, the queue looks like this: 169da6c28aaSamw * 170da6c28aaSamw * outer_current -------v 171da6c28aaSamw * outer_queue_head --> list#1 --0 172da6c28aaSamw * outer_queue_tailp ---------& 173da6c28aaSamw * 174da6c28aaSamw * When the pointer #1.next is encountered, and entry is added to the 175da6c28aaSamw * queue, 176da6c28aaSamw * 177da6c28aaSamw * outer_current -------v 178da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --0 179da6c28aaSamw * outer_queue_tailp --------------------& 180da6c28aaSamw * 181da6c28aaSamw * and the members of #1 continue to be processed, which encounters 182da6c28aaSamw * #1.str: 183da6c28aaSamw * 184da6c28aaSamw * outer_current -------v 185da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "foo" --0 186da6c28aaSamw * outer_queue_tailp ------------------------------& 187da6c28aaSamw * 1888d7e4166Sjose borrego * Upon the completion of list#1, the processing continues by moving to 1898d7e4166Sjose borrego * ndr_stream.outer_current->next, and the tail is set to this outer member: 190da6c28aaSamw * 191da6c28aaSamw * outer_current ------------------v 192da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "foo" --0 193da6c28aaSamw * outer_queue_tailp --------------------& 194da6c28aaSamw * 195da6c28aaSamw * Space for list#2 is allocated, either in the Stub Data or of local 196da6c28aaSamw * memory. When #2.next is encountered, it is found to be the null 197da6c28aaSamw * pointer and no reference is added to the queue. When #2.str is 198da6c28aaSamw * encountered, it is found to be valid, and a reference is added: 199da6c28aaSamw * 200da6c28aaSamw * outer_current ------------------v 201da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 202da6c28aaSamw * outer_queue_tailp ------------------------------& 203da6c28aaSamw * 204da6c28aaSamw * Processing continues in a similar fashion with the string "bar", 205da6c28aaSamw * which is variable-length. At this point, memory for "bar" may be 206da6c28aaSamw * malloc()ed during NDR_M_OP_UNMARSHALL: 207da6c28aaSamw * 208da6c28aaSamw * outer_current -----------------------------v 209da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 210da6c28aaSamw * outer_queue_tailp ------------------------------& 211da6c28aaSamw * 212da6c28aaSamw * And finishes on string "foo". Notice that because "bar" is a 213da6c28aaSamw * variable length string, and we don't know the PDU offset for "foo" 214da6c28aaSamw * until we reach this point. 215da6c28aaSamw * 216da6c28aaSamw * When the queue is drained (current->next==0), processing continues 217da6c28aaSamw * with the next TOP-MOST member. 218da6c28aaSamw * 219da6c28aaSamw * The queue of OUTER constructs manages the variable-length semantics 220da6c28aaSamw * of OUTER constructs and satisfies the depth-first requirement. 221da6c28aaSamw * We allow the queue to linger until the entire TOP-MOST structure is 222da6c28aaSamw * processed as an aid to debugging. 223da6c28aaSamw */ 224da6c28aaSamw 2258d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *); 2268d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *); 227da6c28aaSamw 228da6c28aaSamw /* 229da6c28aaSamw * TOP-MOST ELEMENTS 230da6c28aaSamw * 231da6c28aaSamw * This is fundamentally the first OUTER construct of the parameter, 232da6c28aaSamw * possibly followed by more OUTER constructs due to pointers. The 233da6c28aaSamw * datum (local memory) for TOP-MOST constructs (structs) is allocated 234da6c28aaSamw * by the caller of NDR. 235da6c28aaSamw * 236da6c28aaSamw * After the element is transferred, the outer_queue is drained. 237da6c28aaSamw * 238da6c28aaSamw * All we have to do is add an entry to the outer_queue for this 239da6c28aaSamw * top-most member, and commence the outer_queue processing. 240da6c28aaSamw */ 241da6c28aaSamw int 2428d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum) 243da6c28aaSamw { 2448d7e4166Sjose borrego ndr_ref_t myref; 245da6c28aaSamw 246da6c28aaSamw bzero(&myref, sizeof (myref)); 2478d7e4166Sjose borrego myref.stream = nds; 248da6c28aaSamw myref.datum = datum; 249da6c28aaSamw myref.name = "PROCESS"; 250da6c28aaSamw myref.ti = ti; 251da6c28aaSamw 2528d7e4166Sjose borrego return (ndr_topmost(&myref)); 253da6c28aaSamw } 254da6c28aaSamw 255da6c28aaSamw int 2568d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum) 257da6c28aaSamw { 2588d7e4166Sjose borrego ndr_ref_t myref; 259da6c28aaSamw 260da6c28aaSamw bzero(&myref, sizeof (myref)); 2618d7e4166Sjose borrego myref.stream = nds; 262da6c28aaSamw myref.datum = datum; 263da6c28aaSamw myref.name = "OPERATION"; 264da6c28aaSamw myref.ti = ti; 265da6c28aaSamw myref.inner_flags = NDR_F_SWITCH_IS; 266da6c28aaSamw myref.switch_is = opnum; 267da6c28aaSamw 268da6c28aaSamw if (ti->type_flags != NDR_F_INTERFACE) { 269da6c28aaSamw NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE); 270da6c28aaSamw return (0); 271da6c28aaSamw } 272da6c28aaSamw 273da6c28aaSamw return ((*ti->ndr_func)(&myref)); 274da6c28aaSamw } 275da6c28aaSamw 276da6c28aaSamw int 2778d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref) 278da6c28aaSamw { 2798d7e4166Sjose borrego ndr_typeinfo_t *ti = params_ref->ti; 280da6c28aaSamw 281da6c28aaSamw if (ti->type_flags == NDR_F_OPERATION) 282da6c28aaSamw return (*ti->ndr_func) (params_ref); 283da6c28aaSamw else 2848d7e4166Sjose borrego return (ndr_topmost(params_ref)); 285da6c28aaSamw } 286da6c28aaSamw 287da6c28aaSamw int 2888d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref) 289da6c28aaSamw { 2908d7e4166Sjose borrego ndr_stream_t *nds; 2918d7e4166Sjose borrego ndr_typeinfo_t *ti; 2928d7e4166Sjose borrego ndr_ref_t *outer_ref = 0; 293da6c28aaSamw int is_varlen; 294da6c28aaSamw int is_string; 295da6c28aaSamw int error; 296da6c28aaSamw int rc; 297da6c28aaSamw unsigned n_fixed; 298da6c28aaSamw int params; 299da6c28aaSamw 300da6c28aaSamw assert(top_ref); 301da6c28aaSamw assert(top_ref->stream); 302da6c28aaSamw assert(top_ref->ti); 303da6c28aaSamw 3048d7e4166Sjose borrego nds = top_ref->stream; 305da6c28aaSamw ti = top_ref->ti; 306da6c28aaSamw 307da6c28aaSamw is_varlen = ti->pdu_size_variable_part; 308da6c28aaSamw is_string = NDR_IS_STRING(ti); 309da6c28aaSamw 3108d7e4166Sjose borrego assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp); 3118d7e4166Sjose borrego assert(!nds->outer_current); 312da6c28aaSamw 313da6c28aaSamw params = top_ref->inner_flags & NDR_F_PARAMS_MASK; 314da6c28aaSamw 315da6c28aaSamw switch (params) { 316da6c28aaSamw case NDR_F_NONE: 317da6c28aaSamw case NDR_F_SWITCH_IS: 318da6c28aaSamw if (is_string || is_varlen) { 319da6c28aaSamw error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 320da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 321da6c28aaSamw return (0); 322da6c28aaSamw } 323da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 324da6c28aaSamw break; 325da6c28aaSamw 326da6c28aaSamw case NDR_F_SIZE_IS: 327da6c28aaSamw error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 328da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 329da6c28aaSamw return (0); 330da6c28aaSamw 331da6c28aaSamw case NDR_F_DIMENSION_IS: 332da6c28aaSamw if (is_varlen) { 333da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 334da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 335da6c28aaSamw return (0); 336da6c28aaSamw } 337da6c28aaSamw n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is; 338da6c28aaSamw break; 339da6c28aaSamw 340da6c28aaSamw case NDR_F_IS_POINTER: 341da6c28aaSamw case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 342da6c28aaSamw n_fixed = 4; 343da6c28aaSamw break; 344da6c28aaSamw 345da6c28aaSamw case NDR_F_IS_REFERENCE: 346da6c28aaSamw case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 347da6c28aaSamw n_fixed = 0; 348da6c28aaSamw break; 349da6c28aaSamw 350da6c28aaSamw default: 351da6c28aaSamw error = NDR_ERR_OUTER_PARAMS_BAD; 352da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 353da6c28aaSamw return (0); 354da6c28aaSamw } 355da6c28aaSamw 3568d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(top_ref); 357da6c28aaSamw if (!outer_ref) 358da6c28aaSamw return (0); /* error already set */ 359da6c28aaSamw 360da6c28aaSamw /* 361da6c28aaSamw * Hand-craft the first OUTER construct and directly call 3628d7e4166Sjose borrego * ndr_inner(). Then, run the outer_queue. We do this 3638d7e4166Sjose borrego * because ndr_outer() wants to malloc() memory for 364da6c28aaSamw * the construct, and we already have the memory. 365da6c28aaSamw */ 366da6c28aaSamw 367da6c28aaSamw /* move the flags, etc, around again, undoes enter_outer_queue() */ 368da6c28aaSamw outer_ref->inner_flags = top_ref->inner_flags; 369da6c28aaSamw outer_ref->outer_flags = 0; 370da6c28aaSamw outer_ref->datum = top_ref->datum; 371da6c28aaSamw 372da6c28aaSamw /* All outer constructs start on a mod4 (longword) boundary */ 3738d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 374da6c28aaSamw return (0); /* error already set */ 375da6c28aaSamw 376da6c28aaSamw /* Regardless of what it is, this is where it starts */ 3778d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 378da6c28aaSamw 3798d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_fixed); 380da6c28aaSamw if (!rc) 381da6c28aaSamw return (0); /* error already set */ 382da6c28aaSamw 383da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed; 384da6c28aaSamw 385da6c28aaSamw /* set-up outer_current, as though run_outer_queue() was doing it */ 3868d7e4166Sjose borrego nds->outer_current = outer_ref; 3878d7e4166Sjose borrego nds->outer_queue_tailp = &nds->outer_current->next; 3888d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 389da6c28aaSamw 390da6c28aaSamw /* do the topmost member */ 3918d7e4166Sjose borrego rc = ndr_inner(outer_ref); 392da6c28aaSamw if (!rc) 393da6c28aaSamw return (0); /* error already set */ 394da6c28aaSamw 3958d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 396da6c28aaSamw 397da6c28aaSamw /* advance, as though run_outer_queue() was doing it */ 3988d7e4166Sjose borrego nds->outer_current = nds->outer_current->next; 3998d7e4166Sjose borrego return (ndr_run_outer_queue(nds)); 400da6c28aaSamw } 401da6c28aaSamw 4028d7e4166Sjose borrego static ndr_ref_t * 4038d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref) 404da6c28aaSamw { 4058d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 4068d7e4166Sjose borrego ndr_ref_t *outer_ref; 407da6c28aaSamw 408da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 4098d7e4166Sjose borrego outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref); 410da6c28aaSamw if (!outer_ref) { 411da6c28aaSamw NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED); 412da6c28aaSamw return (0); 413da6c28aaSamw } 414da6c28aaSamw 415da6c28aaSamw *outer_ref = *arg_ref; 416da6c28aaSamw 417da6c28aaSamw /* move advice in inner_flags to outer_flags */ 418da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 419da6c28aaSamw outer_ref->inner_flags = 0; 4208d7e4166Sjose borrego outer_ref->enclosing = nds->outer_current; 421da6c28aaSamw outer_ref->backptr = 0; 422da6c28aaSamw outer_ref->datum = 0; 423da6c28aaSamw 4248d7e4166Sjose borrego assert(nds->outer_queue_tailp); 425da6c28aaSamw 4268d7e4166Sjose borrego outer_ref->next = *nds->outer_queue_tailp; 4278d7e4166Sjose borrego *nds->outer_queue_tailp = outer_ref; 4288d7e4166Sjose borrego nds->outer_queue_tailp = &outer_ref->next; 429da6c28aaSamw return (outer_ref); 430da6c28aaSamw } 431da6c28aaSamw 432da6c28aaSamw int 4338d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds) 434da6c28aaSamw { 4358d7e4166Sjose borrego while (nds->outer_current) { 4368d7e4166Sjose borrego nds->outer_queue_tailp = &nds->outer_current->next; 437da6c28aaSamw 4388d7e4166Sjose borrego if (!ndr_outer(nds->outer_current)) 439da6c28aaSamw return (0); 440da6c28aaSamw 4418d7e4166Sjose borrego nds->outer_current = nds->outer_current->next; 442da6c28aaSamw } 443da6c28aaSamw 444da6c28aaSamw return (1); 445da6c28aaSamw } 446da6c28aaSamw 447da6c28aaSamw /* 448da6c28aaSamw * OUTER CONSTRUCTS 449da6c28aaSamw * 450da6c28aaSamw * OUTER constructs are where the real work is, which stems from the 451da6c28aaSamw * variable-length potential. 452da6c28aaSamw * 453da6c28aaSamw * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT 454da6c28aaSamw * 455da6c28aaSamw * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT, 456da6c28aaSamw * VARYING, and VARYING/CONFORMANT. 457da6c28aaSamw * 458da6c28aaSamw * What makes this so tough is that the variable-length array may be well 459da6c28aaSamw * encapsulated within the outer construct. Further, because DCE(MS)/RPC 460da6c28aaSamw * tries to keep the constructs contiguous in the data stream, the sizing 461da6c28aaSamw * information precedes the entire OUTER construct. The sizing information 462da6c28aaSamw * must be used at the appropriate time, which can be after many, many, 463da6c28aaSamw * many fixed-length elements. During IDL type analysis, we know in 464da6c28aaSamw * advance constructs that encapsulate variable-length constructs. So, 465da6c28aaSamw * we know when we have a sizing header and when we don't. The actual 466da6c28aaSamw * semantics of the header are largely deferred. 467da6c28aaSamw * 468da6c28aaSamw * Currently, VARYING constructs are not implemented but they are described 469da6c28aaSamw * here in case they have to be implemented in the future. Similarly, 470da6c28aaSamw * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently 471da6c28aaSamw * not implemented. Only one-dimensional, variable-length arrays are 472da6c28aaSamw * supported. 473da6c28aaSamw * 474da6c28aaSamw * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW 475da6c28aaSamw * 476da6c28aaSamw * All variable-length values are arrays. These arrays may be embedded 477da6c28aaSamw * well within another construct. However, a variable-length construct 478da6c28aaSamw * may ONLY appear as the last member of an enclosing construct. Example: 479da6c28aaSamw * 480da6c28aaSamw * struct credentials { 481da6c28aaSamw * ulong uid, gid; 482da6c28aaSamw * ulong n_gids; 483da6c28aaSamw * [size_is(n_gids)] 484da6c28aaSamw * ulong gids[*]; // variable-length. 485da6c28aaSamw * }; 486da6c28aaSamw * 487da6c28aaSamw * CONFORMANT constructs have a dynamic size in local memory and in the 488da6c28aaSamw * PDU. The CONFORMANT quality is indicated by the [size_is()] advice. 489da6c28aaSamw * CONFORMANT constructs have the following header: 490da6c28aaSamw * 491da6c28aaSamw * struct conformant_header { 492da6c28aaSamw * ulong size_is; 493da6c28aaSamw * }; 494da6c28aaSamw * 495da6c28aaSamw * (Multi-dimensional CONFORMANT arrays have a similar header for each 496da6c28aaSamw * dimension - not implemented). 497da6c28aaSamw * 498da6c28aaSamw * Example CONFORMANT construct: 499da6c28aaSamw * 500da6c28aaSamw * struct user { 501da6c28aaSamw * char * name; 502da6c28aaSamw * struct credentials cred; // see above 503da6c28aaSamw * }; 504da6c28aaSamw * 505da6c28aaSamw * Consider the data tree: 506da6c28aaSamw * 507da6c28aaSamw * +--------+ 508da6c28aaSamw * | user | 509da6c28aaSamw * +--------+ 510da6c28aaSamw * | name ----> "fred" (the string is a different OUTER) 511da6c28aaSamw * | uid | 512da6c28aaSamw * | gid | 513da6c28aaSamw * | n_gids | for example, 3 514da6c28aaSamw * | gids[0]| 515da6c28aaSamw * | gids[1]| 516da6c28aaSamw * | gids[2]| 517da6c28aaSamw * +--------+ 518da6c28aaSamw * 519da6c28aaSamw * The OUTER construct in the Stub Data would be: 520da6c28aaSamw * 521da6c28aaSamw * +---+---------+---------------------------------------------+ 522da6c28aaSamw * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]| 523da6c28aaSamw * +---+---------+---------------------------------------------+ 524da6c28aaSamw * szing hdr|user |<-------------- user.cred ------------>| 525da6c28aaSamw * |<--- fixed-size ---->|<----- conformant ---->| 526da6c28aaSamw * 527da6c28aaSamw * The ndr_typeinfo for struct user will have: 528da6c28aaSamw * pdu_fixed_size_part = 16 four long words (name uid gid n_gids) 529da6c28aaSamw * pdu_variable_size_part = 4 per element, sizeof gids[0] 530da6c28aaSamw * 531da6c28aaSamw * VARYING CONSTRUCTS -- NOT IMPLEMENTED 532da6c28aaSamw * 533da6c28aaSamw * VARYING constructs have the following header: 534da6c28aaSamw * 535da6c28aaSamw * struct varying_header { 536da6c28aaSamw * ulong first_is; 537da6c28aaSamw * ulong length_is; 538da6c28aaSamw * }; 539da6c28aaSamw * 540da6c28aaSamw * This indicates which interval of an array is significant. 541da6c28aaSamw * Non-intersecting elements of the array are undefined and usually 542da6c28aaSamw * zero-filled. The first_is parameter for C arrays is always 0 for 543da6c28aaSamw * the first element. 544da6c28aaSamw * 545da6c28aaSamw * N.B. Constructs may contain one CONFORMANT element, which is always 546da6c28aaSamw * last, but may contain many VARYING elements, which can be anywhere. 547da6c28aaSamw * 548da6c28aaSamw * VARYING CONFORMANT constructs have the sizing headers arranged like 549da6c28aaSamw * this: 550da6c28aaSamw * 551da6c28aaSamw * struct conformant_header all_conformant[N_CONFORMANT_DIM]; 552da6c28aaSamw * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS]; 553da6c28aaSamw * 554da6c28aaSamw * The sizing header is immediately followed by the values for the 555da6c28aaSamw * construct. Again, we don't support more than one dimension and 556da6c28aaSamw * we don't support VARYING constructs at this time. 557da6c28aaSamw * 558da6c28aaSamw * A good example of a VARYING/CONFORMANT data structure is the UNIX 559da6c28aaSamw * directory entry: 560da6c28aaSamw * 561da6c28aaSamw * struct dirent { 562da6c28aaSamw * ushort reclen; 563da6c28aaSamw * ushort namlen; 564da6c28aaSamw * ulong inum; 565da6c28aaSamw * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL 566da6c28aaSamw * uchar name[*]; 567da6c28aaSamw * }; 568da6c28aaSamw * 569da6c28aaSamw * 570da6c28aaSamw * STRINGS ARE A SPECIAL CASE 571da6c28aaSamw * 572da6c28aaSamw * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures 573da6c28aaSamw * for strings. This is a simple one-dimensional variable-length array, 574da6c28aaSamw * typically with its last element all zeroes. We handle strings with the 575da6c28aaSamw * header: 576da6c28aaSamw * 577da6c28aaSamw * struct string_header { 578da6c28aaSamw * ulong size_is; 579da6c28aaSamw * ulong first_is; // always 0 580da6c28aaSamw * ulong length_is; // always same as size_is 581da6c28aaSamw * }; 582da6c28aaSamw * 583da6c28aaSamw * If general support for VARYING and VARYING/CONFORMANT mechanisms is 584da6c28aaSamw * implemented, we probably won't need the strings special case. 585da6c28aaSamw */ 586da6c28aaSamw int 5878d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref) 588da6c28aaSamw { 5898d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 5908d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 591da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 592da6c28aaSamw int is_union = NDR_IS_UNION(ti); 593da6c28aaSamw int is_string = NDR_IS_STRING(ti); 594da6c28aaSamw int error = NDR_ERR_OUTER_PARAMS_BAD; 595da6c28aaSamw int params; 596da6c28aaSamw 597da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 598da6c28aaSamw 599da6c28aaSamw NDR_TATTLE(outer_ref, "--OUTER--"); 600da6c28aaSamw 601da6c28aaSamw /* All outer constructs start on a mod4 (longword) boundary */ 6028d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 603da6c28aaSamw return (0); /* error already set */ 604da6c28aaSamw 605da6c28aaSamw /* Regardless of what it is, this is where it starts */ 6068d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 607da6c28aaSamw 608da6c28aaSamw if (is_union) { 609da6c28aaSamw error = NDR_ERR_OUTER_UNION_ILLEGAL; 610da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 611da6c28aaSamw return (0); 612da6c28aaSamw } 613da6c28aaSamw 614da6c28aaSamw switch (params) { 615da6c28aaSamw case NDR_F_NONE: 616da6c28aaSamw if (is_string) 6178d7e4166Sjose borrego return (ndr_outer_string(outer_ref)); 618da6c28aaSamw if (is_varlen) 6198d7e4166Sjose borrego return (ndr_outer_conformant_construct(outer_ref)); 620da6c28aaSamw 6218d7e4166Sjose borrego return (ndr_outer_fixed(outer_ref)); 622da6c28aaSamw 623da6c28aaSamw case NDR_F_SIZE_IS: 624da6c28aaSamw case NDR_F_DIMENSION_IS: 625f96bd5c8SAlan Wright case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 626f96bd5c8SAlan Wright case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 627da6c28aaSamw if (is_varlen) { 628da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 629da6c28aaSamw break; 630da6c28aaSamw } 631da6c28aaSamw 632f96bd5c8SAlan Wright if (params & NDR_F_SIZE_IS) 6338d7e4166Sjose borrego return (ndr_outer_conformant_array(outer_ref)); 634da6c28aaSamw else 6358d7e4166Sjose borrego return (ndr_outer_fixed_array(outer_ref)); 636da6c28aaSamw 637da6c28aaSamw default: 638da6c28aaSamw error = NDR_ERR_OUTER_PARAMS_BAD; 639da6c28aaSamw break; 640da6c28aaSamw } 641da6c28aaSamw 642da6c28aaSamw /* 643da6c28aaSamw * If we get here, something is wrong. Most likely, 644da6c28aaSamw * the params flags do not match. 645da6c28aaSamw */ 646da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 647da6c28aaSamw return (0); 648da6c28aaSamw } 649da6c28aaSamw 650da6c28aaSamw int 6518d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref) 652da6c28aaSamw { 6538d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 6548d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 6558d7e4166Sjose borrego ndr_ref_t myref; 656da6c28aaSamw char *valp = NULL; 657da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 658da6c28aaSamw int is_union = NDR_IS_UNION(ti); 659da6c28aaSamw int is_string = NDR_IS_STRING(ti); 660da6c28aaSamw int rc; 661da6c28aaSamw unsigned n_hdr; 662da6c28aaSamw unsigned n_fixed; 663da6c28aaSamw unsigned n_variable; 664da6c28aaSamw unsigned n_alloc; 665da6c28aaSamw unsigned n_pdu_total; 666da6c28aaSamw int params; 667da6c28aaSamw 668da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 669da6c28aaSamw 670da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 671da6c28aaSamw assert(params == NDR_F_NONE); 672da6c28aaSamw 673da6c28aaSamw /* no header for this */ 674da6c28aaSamw n_hdr = 0; 675da6c28aaSamw 676da6c28aaSamw /* fixed part -- exactly one of these */ 677da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 678da6c28aaSamw assert(n_fixed > 0); 679da6c28aaSamw 680da6c28aaSamw /* variable part -- exactly none of these */ 681da6c28aaSamw n_variable = 0; 682da6c28aaSamw 683da6c28aaSamw /* sum them up to determine the PDU space required */ 684da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 685da6c28aaSamw 686da6c28aaSamw /* similar sum to determine how much local memory is required */ 687da6c28aaSamw n_alloc = n_fixed + n_variable; 688da6c28aaSamw 6898d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 690da6c28aaSamw if (!rc) 691da6c28aaSamw return (rc); /* error already set */ 692da6c28aaSamw 6938d7e4166Sjose borrego switch (nds->m_op) { 694da6c28aaSamw case NDR_M_OP_MARSHALL: 695da6c28aaSamw valp = outer_ref->datum; 69696a62adaSjoyce mcintosh if (!valp) { 69796a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 69896a62adaSjoyce mcintosh return (0); 69996a62adaSjoyce mcintosh } 700f96bd5c8SAlan Wright if (outer_ref->backptr) 701da6c28aaSamw assert(valp == *outer_ref->backptr); 702da6c28aaSamw break; 703da6c28aaSamw 704da6c28aaSamw case NDR_M_OP_UNMARSHALL: 7058d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 706da6c28aaSamw if (!valp) { 707da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 708da6c28aaSamw return (0); 709da6c28aaSamw } 710da6c28aaSamw if (outer_ref->backptr) 711da6c28aaSamw *outer_ref->backptr = valp; 712da6c28aaSamw outer_ref->datum = valp; 713da6c28aaSamw break; 714da6c28aaSamw 715da6c28aaSamw default: 716da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 717da6c28aaSamw return (0); 718da6c28aaSamw } 719da6c28aaSamw 720da6c28aaSamw bzero(&myref, sizeof (myref)); 7218d7e4166Sjose borrego myref.stream = nds; 722da6c28aaSamw myref.enclosing = outer_ref; 723da6c28aaSamw myref.ti = outer_ref->ti; 724da6c28aaSamw myref.datum = outer_ref->datum; 725da6c28aaSamw myref.name = "FIXED-VALUE"; 726da6c28aaSamw myref.outer_flags = NDR_F_NONE; 727da6c28aaSamw myref.inner_flags = NDR_F_NONE; 728da6c28aaSamw 729da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset; 730da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 731da6c28aaSamw 7328d7e4166Sjose borrego rc = ndr_inner(&myref); 733da6c28aaSamw if (!rc) 734da6c28aaSamw return (rc); /* error already set */ 735da6c28aaSamw 7368d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 737da6c28aaSamw return (1); 738da6c28aaSamw } 739da6c28aaSamw 740da6c28aaSamw int 7418d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref) 742da6c28aaSamw { 7438d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 7448d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 7458d7e4166Sjose borrego ndr_ref_t myref; 746da6c28aaSamw char *valp = NULL; 747da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 748da6c28aaSamw int is_union = NDR_IS_UNION(ti); 749da6c28aaSamw int is_string = NDR_IS_STRING(ti); 750da6c28aaSamw int rc; 751da6c28aaSamw unsigned n_hdr; 752da6c28aaSamw unsigned n_fixed; 753da6c28aaSamw unsigned n_variable; 754da6c28aaSamw unsigned n_alloc; 755da6c28aaSamw unsigned n_pdu_total; 756da6c28aaSamw int params; 757da6c28aaSamw 758da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 759da6c28aaSamw 760da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 761da6c28aaSamw assert(params == NDR_F_DIMENSION_IS); 762da6c28aaSamw 763da6c28aaSamw /* no header for this */ 764da6c28aaSamw n_hdr = 0; 765da6c28aaSamw 766da6c28aaSamw /* fixed part -- exactly dimension_is of these */ 767da6c28aaSamw n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 768da6c28aaSamw assert(n_fixed > 0); 769da6c28aaSamw 770da6c28aaSamw /* variable part -- exactly none of these */ 771da6c28aaSamw n_variable = 0; 772da6c28aaSamw 773da6c28aaSamw /* sum them up to determine the PDU space required */ 774da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 775da6c28aaSamw 776da6c28aaSamw /* similar sum to determine how much local memory is required */ 777da6c28aaSamw n_alloc = n_fixed + n_variable; 778da6c28aaSamw 7798d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 780da6c28aaSamw if (!rc) 781da6c28aaSamw return (rc); /* error already set */ 782da6c28aaSamw 7838d7e4166Sjose borrego switch (nds->m_op) { 784da6c28aaSamw case NDR_M_OP_MARSHALL: 785da6c28aaSamw valp = outer_ref->datum; 78696a62adaSjoyce mcintosh if (!valp) { 78796a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 78896a62adaSjoyce mcintosh return (0); 78996a62adaSjoyce mcintosh } 790f96bd5c8SAlan Wright if (outer_ref->backptr) 791da6c28aaSamw assert(valp == *outer_ref->backptr); 792da6c28aaSamw break; 793da6c28aaSamw 794da6c28aaSamw case NDR_M_OP_UNMARSHALL: 7958d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 796da6c28aaSamw if (!valp) { 797da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 798da6c28aaSamw return (0); 799da6c28aaSamw } 800da6c28aaSamw if (outer_ref->backptr) 801da6c28aaSamw *outer_ref->backptr = valp; 802da6c28aaSamw outer_ref->datum = valp; 803da6c28aaSamw break; 804da6c28aaSamw 805da6c28aaSamw default: 806da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 807da6c28aaSamw return (0); 808da6c28aaSamw } 809da6c28aaSamw 810da6c28aaSamw bzero(&myref, sizeof (myref)); 8118d7e4166Sjose borrego myref.stream = nds; 812da6c28aaSamw myref.enclosing = outer_ref; 813da6c28aaSamw myref.ti = outer_ref->ti; 814da6c28aaSamw myref.datum = outer_ref->datum; 815da6c28aaSamw myref.name = "FIXED-ARRAY"; 816da6c28aaSamw myref.outer_flags = NDR_F_NONE; 817da6c28aaSamw myref.inner_flags = NDR_F_DIMENSION_IS; 818da6c28aaSamw myref.dimension_is = outer_ref->dimension_is; 819da6c28aaSamw 820da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset; 821da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 822da6c28aaSamw 8238d7e4166Sjose borrego rc = ndr_inner(&myref); 824da6c28aaSamw if (!rc) 825da6c28aaSamw return (rc); /* error already set */ 826da6c28aaSamw 8278d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 828da6c28aaSamw return (1); 829da6c28aaSamw } 830da6c28aaSamw 831da6c28aaSamw int 8328d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref) 833da6c28aaSamw { 8348d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 8358d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 8368d7e4166Sjose borrego ndr_ref_t myref; 837da6c28aaSamw char *valp = NULL; 838da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 839da6c28aaSamw int is_union = NDR_IS_UNION(ti); 840da6c28aaSamw int is_string = NDR_IS_STRING(ti); 841da6c28aaSamw unsigned long size_is; 842da6c28aaSamw int rc; 843da6c28aaSamw unsigned n_hdr; 844da6c28aaSamw unsigned n_fixed; 845da6c28aaSamw unsigned n_variable; 846da6c28aaSamw unsigned n_alloc; 847da6c28aaSamw unsigned n_pdu_total; 848f96bd5c8SAlan Wright unsigned n_ptr_offset; 849da6c28aaSamw int params; 850da6c28aaSamw 851da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 852da6c28aaSamw 853da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 854f96bd5c8SAlan Wright assert(params & NDR_F_SIZE_IS); 855da6c28aaSamw 856da6c28aaSamw /* conformant header for this */ 857da6c28aaSamw n_hdr = 4; 858da6c28aaSamw 859da6c28aaSamw /* fixed part -- exactly none of these */ 860da6c28aaSamw n_fixed = 0; 861da6c28aaSamw 862da6c28aaSamw /* variable part -- exactly size_of of these */ 863da6c28aaSamw /* notice that it is the **fixed** size of the ti */ 864da6c28aaSamw n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 865da6c28aaSamw 866da6c28aaSamw /* sum them up to determine the PDU space required */ 867da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 868da6c28aaSamw 869da6c28aaSamw /* similar sum to determine how much local memory is required */ 870da6c28aaSamw n_alloc = n_fixed + n_variable; 871da6c28aaSamw 8728d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 873da6c28aaSamw if (!rc) 874da6c28aaSamw return (rc); /* error already set */ 875da6c28aaSamw 8768d7e4166Sjose borrego switch (nds->m_op) { 877da6c28aaSamw case NDR_M_OP_MARSHALL: 878da6c28aaSamw size_is = outer_ref->size_is; 8798d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 880da6c28aaSamw if (!rc) 881da6c28aaSamw return (0); /* error already set */ 882da6c28aaSamw 883da6c28aaSamw valp = outer_ref->datum; 88496a62adaSjoyce mcintosh if (!valp) { 88596a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 88696a62adaSjoyce mcintosh return (0); 88796a62adaSjoyce mcintosh } 888f96bd5c8SAlan Wright if (outer_ref->backptr) 889da6c28aaSamw assert(valp == *outer_ref->backptr); 890f96bd5c8SAlan Wright n_ptr_offset = 4; 891da6c28aaSamw break; 892da6c28aaSamw 893da6c28aaSamw case NDR_M_OP_UNMARSHALL: 894f96bd5c8SAlan Wright if (params & NDR_F_IS_REFERENCE) { 895f96bd5c8SAlan Wright size_is = outer_ref->size_is; 896f96bd5c8SAlan Wright n_ptr_offset = 0; 897f96bd5c8SAlan Wright } else { 898f96bd5c8SAlan Wright /* NDR_F_IS_POINTER */ 899f96bd5c8SAlan Wright rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 900f96bd5c8SAlan Wright if (!rc) 901f96bd5c8SAlan Wright return (0); /* error already set */ 902f96bd5c8SAlan Wright 903f96bd5c8SAlan Wright if (size_is != outer_ref->size_is) { 904f96bd5c8SAlan Wright NDR_SET_ERROR(outer_ref, 905f96bd5c8SAlan Wright NDR_ERR_SIZE_IS_MISMATCH_PDU); 906f96bd5c8SAlan Wright return (0); 907f96bd5c8SAlan Wright } 908da6c28aaSamw 909f96bd5c8SAlan Wright n_ptr_offset = 4; 910da6c28aaSamw } 911da6c28aaSamw 9123ad684d6Sjb if (size_is > 0) { 9138d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 9143ad684d6Sjb if (!valp) { 9153ad684d6Sjb NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 9163ad684d6Sjb return (0); 9173ad684d6Sjb } 918da6c28aaSamw } 9193ad684d6Sjb 920da6c28aaSamw if (outer_ref->backptr) 921da6c28aaSamw *outer_ref->backptr = valp; 922da6c28aaSamw outer_ref->datum = valp; 923da6c28aaSamw break; 924da6c28aaSamw 925da6c28aaSamw default: 926da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 927da6c28aaSamw return (0); 928da6c28aaSamw } 929da6c28aaSamw 930da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 931da6c28aaSamw outer_ref->type_flags = NDR_F_NONE; 932da6c28aaSamw outer_ref->inner_flags = NDR_F_NONE; 933da6c28aaSamw 9343ad684d6Sjb if (size_is > 0) { 9353ad684d6Sjb bzero(&myref, sizeof (myref)); 9368d7e4166Sjose borrego myref.stream = nds; 9373ad684d6Sjb myref.enclosing = outer_ref; 9383ad684d6Sjb myref.ti = outer_ref->ti; 9393ad684d6Sjb myref.datum = outer_ref->datum; 9403ad684d6Sjb myref.name = "CONFORMANT-ARRAY"; 9413ad684d6Sjb myref.outer_flags = NDR_F_NONE; 9423ad684d6Sjb myref.inner_flags = NDR_F_SIZE_IS; 9433ad684d6Sjb myref.size_is = outer_ref->size_is; 9443ad684d6Sjb 9453ad684d6Sjb myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 9463ad684d6Sjb myref.dimension_is = outer_ref->size_is; /* convenient */ 9473ad684d6Sjb 948f96bd5c8SAlan Wright myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset; 9493ad684d6Sjb 9508d7e4166Sjose borrego rc = ndr_inner(&myref); 9513ad684d6Sjb if (!rc) 9523ad684d6Sjb return (rc); /* error already set */ 9533ad684d6Sjb } 954da6c28aaSamw 9558d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 956da6c28aaSamw return (1); 957da6c28aaSamw } 958da6c28aaSamw 959da6c28aaSamw int 9608d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref) 961da6c28aaSamw { 9628d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 9638d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 9648d7e4166Sjose borrego ndr_ref_t myref; 965da6c28aaSamw char *valp = NULL; 966da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 967da6c28aaSamw int is_union = NDR_IS_UNION(ti); 968da6c28aaSamw int is_string = NDR_IS_STRING(ti); 969da6c28aaSamw unsigned long size_is; 970da6c28aaSamw int rc; 971da6c28aaSamw unsigned n_hdr; 972da6c28aaSamw unsigned n_fixed; 973da6c28aaSamw unsigned n_variable; 974da6c28aaSamw unsigned n_alloc; 975da6c28aaSamw unsigned n_pdu_total; 976da6c28aaSamw int params; 977da6c28aaSamw 978da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 979da6c28aaSamw 980da6c28aaSamw assert(is_varlen && !is_string && !is_union); 981da6c28aaSamw assert(params == NDR_F_NONE); 982da6c28aaSamw 983da6c28aaSamw /* conformant header for this */ 984da6c28aaSamw n_hdr = 4; 985da6c28aaSamw 986da6c28aaSamw /* fixed part -- exactly one of these */ 987da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 988da6c28aaSamw 989da6c28aaSamw /* variable part -- exactly size_of of these */ 990da6c28aaSamw n_variable = 0; /* 0 for the moment */ 991da6c28aaSamw 992da6c28aaSamw /* sum them up to determine the PDU space required */ 993da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 994da6c28aaSamw 995da6c28aaSamw /* similar sum to determine how much local memory is required */ 996da6c28aaSamw n_alloc = n_fixed + n_variable; 997da6c28aaSamw 998da6c28aaSamw /* For the moment, grow enough for the fixed-size part */ 9998d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1000da6c28aaSamw if (!rc) 1001da6c28aaSamw return (rc); /* error already set */ 1002da6c28aaSamw 10038d7e4166Sjose borrego switch (nds->m_op) { 1004da6c28aaSamw case NDR_M_OP_MARSHALL: 1005da6c28aaSamw /* 1006da6c28aaSamw * We don't know the size yet. We have to wait for 1007da6c28aaSamw * it. Proceed with the fixed-size part, and await 10088d7e4166Sjose borrego * the call to ndr_size_is(). 1009da6c28aaSamw */ 1010da6c28aaSamw size_is = 0; 10118d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1012da6c28aaSamw if (!rc) 1013da6c28aaSamw return (0); /* error already set */ 1014da6c28aaSamw 1015da6c28aaSamw valp = outer_ref->datum; 101696a62adaSjoyce mcintosh if (!valp) { 101796a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 101896a62adaSjoyce mcintosh return (0); 101996a62adaSjoyce mcintosh } 1020f96bd5c8SAlan Wright if (outer_ref->backptr) 1021da6c28aaSamw assert(valp == *outer_ref->backptr); 1022da6c28aaSamw break; 1023da6c28aaSamw 1024da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1025da6c28aaSamw /* 1026da6c28aaSamw * We know the size of the variable part because 1027da6c28aaSamw * of the CONFORMANT header. We will verify 1028da6c28aaSamw * the header against the [size_is(X)] advice 10298d7e4166Sjose borrego * later when ndr_size_is() is called. 1030da6c28aaSamw */ 10318d7e4166Sjose borrego rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 1032da6c28aaSamw if (!rc) 1033da6c28aaSamw return (0); /* error already set */ 1034da6c28aaSamw 1035da6c28aaSamw /* recalculate metrics */ 1036da6c28aaSamw n_variable = size_is * ti->pdu_size_variable_part; 1037da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1038da6c28aaSamw n_alloc = n_fixed + n_variable; 1039da6c28aaSamw 10408d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1041da6c28aaSamw if (!rc) 1042da6c28aaSamw return (rc); /* error already set */ 1043da6c28aaSamw 1044da6c28aaSamw outer_ref->size_is = size_is; /* verified later */ 1045da6c28aaSamw 10468d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1047da6c28aaSamw if (!valp) { 1048da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1049da6c28aaSamw return (0); 1050da6c28aaSamw } 1051da6c28aaSamw if (outer_ref->backptr) 1052da6c28aaSamw *outer_ref->backptr = valp; 1053da6c28aaSamw outer_ref->datum = valp; 1054da6c28aaSamw break; 1055da6c28aaSamw 1056da6c28aaSamw default: 1057da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1058da6c28aaSamw return (0); 1059da6c28aaSamw } 1060da6c28aaSamw 10613ad684d6Sjb outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 10623ad684d6Sjb outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 10633ad684d6Sjb outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 10643ad684d6Sjb 1065da6c28aaSamw bzero(&myref, sizeof (myref)); 10668d7e4166Sjose borrego myref.stream = nds; 1067da6c28aaSamw myref.enclosing = outer_ref; 1068da6c28aaSamw myref.ti = outer_ref->ti; 1069da6c28aaSamw myref.datum = outer_ref->datum; 1070da6c28aaSamw myref.name = "CONFORMANT-CONSTRUCT"; 1071da6c28aaSamw myref.outer_flags = NDR_F_NONE; 1072da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1073da6c28aaSamw myref.size_is = outer_ref->size_is; 1074da6c28aaSamw 1075da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset + 4; 1076da6c28aaSamw 10778d7e4166Sjose borrego rc = ndr_inner(&myref); 1078da6c28aaSamw if (!rc) 1079da6c28aaSamw return (rc); /* error already set */ 1080da6c28aaSamw 10818d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1082da6c28aaSamw 1083da6c28aaSamw if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 1084da6c28aaSamw NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 1085da6c28aaSamw return (0); 1086da6c28aaSamw } 1087da6c28aaSamw 1088da6c28aaSamw return (1); 1089da6c28aaSamw } 1090da6c28aaSamw 1091da6c28aaSamw int 10928d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref) 1093da6c28aaSamw { 10948d7e4166Sjose borrego ndr_stream_t *nds = ref->stream; 10958d7e4166Sjose borrego ndr_ref_t *outer_ref = nds->outer_current; 10968d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 1097da6c28aaSamw unsigned long size_is; 1098da6c28aaSamw int rc; 1099da6c28aaSamw unsigned n_hdr; 1100da6c28aaSamw unsigned n_fixed; 1101da6c28aaSamw unsigned n_variable; 1102da6c28aaSamw unsigned n_pdu_total; 1103da6c28aaSamw 1104da6c28aaSamw assert(ref->inner_flags & NDR_F_SIZE_IS); 1105da6c28aaSamw size_is = ref->size_is; 1106da6c28aaSamw 1107da6c28aaSamw if (outer_ref->type_flags != NDR_F_SIZE_IS) { 1108da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 1109da6c28aaSamw return (0); 1110da6c28aaSamw } 1111da6c28aaSamw 1112da6c28aaSamw if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 1113da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 1114da6c28aaSamw return (0); 1115da6c28aaSamw } 1116da6c28aaSamw 11178d7e4166Sjose borrego /* repeat metrics, see ndr_conformant_construct() above */ 1118da6c28aaSamw n_hdr = 4; 1119da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 1120da6c28aaSamw n_variable = size_is * ti->pdu_size_variable_part; 1121da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1122da6c28aaSamw 11238d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1124da6c28aaSamw if (!rc) 1125da6c28aaSamw return (rc); /* error already set */ 1126da6c28aaSamw 11278d7e4166Sjose borrego switch (nds->m_op) { 1128da6c28aaSamw case NDR_M_OP_MARSHALL: 1129da6c28aaSamw /* 1130da6c28aaSamw * We have to set the sizing header and extend 1131da6c28aaSamw * the size of the PDU (already done). 1132da6c28aaSamw */ 11338d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1134da6c28aaSamw if (!rc) 1135da6c28aaSamw return (0); /* error already set */ 1136da6c28aaSamw break; 1137da6c28aaSamw 1138da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1139da6c28aaSamw /* 11408d7e4166Sjose borrego * Allocation done during ndr_conformant_construct(). 1141da6c28aaSamw * All we are doing here is verifying that the 1142da6c28aaSamw * intended size (ref->size_is) matches the sizing header. 1143da6c28aaSamw */ 1144da6c28aaSamw if (size_is != outer_ref->size_is) { 1145da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 1146da6c28aaSamw return (0); 1147da6c28aaSamw } 1148da6c28aaSamw break; 1149da6c28aaSamw 1150da6c28aaSamw default: 1151da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1152da6c28aaSamw return (0); 1153da6c28aaSamw } 1154da6c28aaSamw 1155da6c28aaSamw outer_ref->inner_flags |= NDR_F_SIZE_IS; 1156da6c28aaSamw outer_ref->size_is = ref->size_is; 1157da6c28aaSamw return (1); 1158da6c28aaSamw } 1159da6c28aaSamw 1160da6c28aaSamw int 11618d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref) 1162da6c28aaSamw { 11638d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 11648d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 11658d7e4166Sjose borrego ndr_ref_t myref; 1166da6c28aaSamw char *valp = NULL; 1167da6c28aaSamw unsigned is_varlen = ti->pdu_size_variable_part; 1168da6c28aaSamw int is_union = NDR_IS_UNION(ti); 1169da6c28aaSamw int is_string = NDR_IS_STRING(ti); 1170da6c28aaSamw int rc; 1171da6c28aaSamw unsigned n_zeroes; 1172da6c28aaSamw unsigned ix; 1173da6c28aaSamw unsigned long size_is; 1174da6c28aaSamw unsigned long first_is; 1175da6c28aaSamw unsigned long length_is; 1176da6c28aaSamw unsigned n_hdr; 1177da6c28aaSamw unsigned n_fixed; 1178da6c28aaSamw unsigned n_variable; 1179da6c28aaSamw unsigned n_alloc; 1180da6c28aaSamw unsigned n_pdu_total; 1181da6c28aaSamw int params; 1182da6c28aaSamw 1183da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 1184da6c28aaSamw 1185da6c28aaSamw assert(is_varlen && is_string && !is_union); 1186da6c28aaSamw assert(params == NDR_F_NONE); 1187da6c28aaSamw 1188da6c28aaSamw /* string header for this: size_is first_is length_is */ 1189da6c28aaSamw n_hdr = 12; 1190da6c28aaSamw 1191da6c28aaSamw /* fixed part -- exactly none of these */ 1192da6c28aaSamw n_fixed = 0; 1193da6c28aaSamw 11948d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_hdr)) 1195da6c28aaSamw return (0); /* error already set */ 1196da6c28aaSamw 11978d7e4166Sjose borrego switch (nds->m_op) { 1198da6c28aaSamw case NDR_M_OP_MARSHALL: 1199da6c28aaSamw valp = outer_ref->datum; 120096a62adaSjoyce mcintosh if (!valp) { 120196a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 120296a62adaSjoyce mcintosh return (0); 120396a62adaSjoyce mcintosh } 1204da6c28aaSamw 1205da6c28aaSamw if (outer_ref->backptr) 1206da6c28aaSamw assert(valp == *outer_ref->backptr); 1207da6c28aaSamw 1208da6c28aaSamw if (ti == &ndt_s_wchar) { 1209da6c28aaSamw /* 1210a0aa776eSAlan Wright * size_is is the number of characters in the 1211a0aa776eSAlan Wright * (multibyte) string, including the null. 12123299f39fSGordon Ross * In other words, symbols, not bytes. 1213da6c28aaSamw */ 12143299f39fSGordon Ross size_t wlen; 12153299f39fSGordon Ross wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX); 12163299f39fSGordon Ross if (wlen == (size_t)-1) { 12173299f39fSGordon Ross /* illegal sequence error? */ 1218da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1219da6c28aaSamw return (0); 1220da6c28aaSamw } 12213299f39fSGordon Ross if ((nds->flags & NDS_F_NONULL) == 0) 12223299f39fSGordon Ross wlen++; 12233299f39fSGordon Ross if (wlen > NDR_STRING_MAX) { 12243299f39fSGordon Ross NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 12253299f39fSGordon Ross return (0); 12263299f39fSGordon Ross } 12273299f39fSGordon Ross size_is = wlen; 1228da6c28aaSamw } else { 1229da6c28aaSamw valp = outer_ref->datum; 1230da6c28aaSamw n_zeroes = 0; 1231f96bd5c8SAlan Wright for (ix = 0; ix < NDR_STRING_MAX; ix++) { 1232da6c28aaSamw if (valp[ix] == 0) { 1233da6c28aaSamw n_zeroes++; 1234da6c28aaSamw if (n_zeroes >= is_varlen && 1235da6c28aaSamw ix % is_varlen == 0) { 1236da6c28aaSamw break; 1237da6c28aaSamw } 1238da6c28aaSamw } else { 1239da6c28aaSamw n_zeroes = 0; 1240da6c28aaSamw } 1241da6c28aaSamw } 1242f96bd5c8SAlan Wright if (ix >= NDR_STRING_MAX) { 1243da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1244da6c28aaSamw return (0); 1245da6c28aaSamw } 1246da6c28aaSamw size_is = ix+1; 1247da6c28aaSamw } 1248da6c28aaSamw 1249da6c28aaSamw first_is = 0; 125055bf511dSas 12518d7e4166Sjose borrego if (nds->flags & NDS_F_NOTERM) 125255bf511dSas length_is = size_is - 1; 125355bf511dSas else 125455bf511dSas length_is = size_is; 1255da6c28aaSamw 12568d7e4166Sjose borrego if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) || 12578d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 4, &first_is) || 12588d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 8, &length_is)) 1259da6c28aaSamw return (0); /* error already set */ 1260da6c28aaSamw break; 1261da6c28aaSamw 1262da6c28aaSamw case NDR_M_OP_UNMARSHALL: 12638d7e4166Sjose borrego if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) || 12648d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 4, &first_is) || 12658d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 8, &length_is)) 1266da6c28aaSamw return (0); /* error already set */ 1267da6c28aaSamw 1268da6c28aaSamw /* 1269da6c28aaSamw * In addition to the first_is check, we used to check that 1270da6c28aaSamw * size_is or size_is-1 was equal to length_is but Windows95 1271da6c28aaSamw * doesn't conform to this "rule" (see variable part below). 1272da6c28aaSamw * The srvmgr tool for Windows95 sent the following values 1273da6c28aaSamw * for a path string: 1274da6c28aaSamw * 1275da6c28aaSamw * size_is = 261 (0x105) 1276da6c28aaSamw * first_is = 0 1277da6c28aaSamw * length_is = 53 (0x35) 1278da6c28aaSamw * 1279da6c28aaSamw * The length_is was correct (for the given path) but the 1280da6c28aaSamw * size_is was the maximum path length rather than being 1281da6c28aaSamw * related to length_is. 1282da6c28aaSamw */ 1283da6c28aaSamw if (first_is != 0) { 1284da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1285da6c28aaSamw return (0); 1286da6c28aaSamw } 1287da6c28aaSamw 1288da6c28aaSamw if (ti == &ndt_s_wchar) { 1289da6c28aaSamw /* 1290da6c28aaSamw * Decoding Unicode to UTF-8; we need to allow 1291da6c28aaSamw * for the maximum possible char size. It would 1292da6c28aaSamw * be nice to use mbequiv_strlen but the string 1293da6c28aaSamw * may not be null terminated. 1294da6c28aaSamw */ 12953299f39fSGordon Ross n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX; 1296da6c28aaSamw } else { 1297da6c28aaSamw n_alloc = (size_is + 1) * is_varlen; 1298da6c28aaSamw } 1299da6c28aaSamw 13008d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1301da6c28aaSamw if (!valp) { 1302da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1303da6c28aaSamw return (0); 1304da6c28aaSamw } 1305da6c28aaSamw 1306da6c28aaSamw bzero(valp, (size_is+1) * is_varlen); 1307da6c28aaSamw 1308da6c28aaSamw if (outer_ref->backptr) 1309da6c28aaSamw *outer_ref->backptr = valp; 1310da6c28aaSamw outer_ref->datum = valp; 1311da6c28aaSamw break; 1312da6c28aaSamw 1313da6c28aaSamw default: 1314da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1315da6c28aaSamw return (0); 1316da6c28aaSamw } 1317da6c28aaSamw 1318da6c28aaSamw /* 1319da6c28aaSamw * Variable part - exactly length_is of these. 1320da6c28aaSamw * 1321da6c28aaSamw * Usually, length_is is same as size_is and includes nul. 1322da6c28aaSamw * Some protocols use length_is = size_is-1, and length_is does 1323da6c28aaSamw * not include the nul (which is more consistent with DCE spec). 1324da6c28aaSamw * If the length_is is 0, there is no data following the 1325da6c28aaSamw * sizing header, regardless of size_is. 1326da6c28aaSamw */ 1327da6c28aaSamw n_variable = length_is * is_varlen; 1328da6c28aaSamw 1329da6c28aaSamw /* sum them up to determine the PDU space required */ 1330da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1331da6c28aaSamw 1332da6c28aaSamw /* similar sum to determine how much local memory is required */ 1333da6c28aaSamw n_alloc = n_fixed + n_variable; 1334da6c28aaSamw 13358d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1336da6c28aaSamw if (!rc) 1337da6c28aaSamw return (rc); /* error already set */ 1338da6c28aaSamw 1339da6c28aaSamw if (length_is > 0) { 1340da6c28aaSamw bzero(&myref, sizeof (myref)); 13418d7e4166Sjose borrego myref.stream = nds; 1342da6c28aaSamw myref.enclosing = outer_ref; 1343da6c28aaSamw myref.ti = outer_ref->ti; 1344da6c28aaSamw myref.datum = outer_ref->datum; 1345da6c28aaSamw myref.name = "OUTER-STRING"; 1346da6c28aaSamw myref.outer_flags = NDR_F_IS_STRING; 1347da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1348da6c28aaSamw 1349da6c28aaSamw /* 13508d7e4166Sjose borrego * Set up size_is and strlen_is for ndr_s_wchar. 1351da6c28aaSamw */ 1352dc20a302Sas myref.size_is = size_is; 1353da6c28aaSamw myref.strlen_is = length_is; 1354da6c28aaSamw } 1355da6c28aaSamw 1356da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset + 12; 1357da6c28aaSamw 1358da6c28aaSamw /* 1359da6c28aaSamw * Don't try to decode empty strings. 1360da6c28aaSamw */ 1361da6c28aaSamw if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 13628d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1363da6c28aaSamw return (1); 1364da6c28aaSamw } 1365da6c28aaSamw 1366da6c28aaSamw if ((size_is != 0) && (length_is != 0)) { 13678d7e4166Sjose borrego rc = ndr_inner(&myref); 1368da6c28aaSamw if (!rc) 1369da6c28aaSamw return (rc); /* error already set */ 1370da6c28aaSamw } 1371da6c28aaSamw 13728d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1373da6c28aaSamw return (1); 1374da6c28aaSamw } 1375da6c28aaSamw 1376da6c28aaSamw int 13778d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset, 1378da6c28aaSamw unsigned long *sizing_p) 1379da6c28aaSamw { 13808d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 13818d7e4166Sjose borrego unsigned long pdu_offset; 13828d7e4166Sjose borrego int rc; 1383da6c28aaSamw 1384da6c28aaSamw pdu_offset = outer_ref->pdu_offset + offset; 1385da6c28aaSamw 13868d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 13878d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 13888d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1389da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1390da6c28aaSamw return (0); 1391da6c28aaSamw } 1392da6c28aaSamw 13938d7e4166Sjose borrego switch (nds->m_op) { 1394da6c28aaSamw case NDR_M_OP_MARSHALL: 1395da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1396da6c28aaSamw return (0); 1397da6c28aaSamw 1398da6c28aaSamw case NDR_M_OP_UNMARSHALL: 13998d7e4166Sjose borrego rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14008d7e4166Sjose borrego nds->swap, outer_ref); 1401da6c28aaSamw break; 1402da6c28aaSamw 1403da6c28aaSamw default: 1404da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1405da6c28aaSamw return (0); 1406da6c28aaSamw } 1407da6c28aaSamw 1408da6c28aaSamw return (rc); 1409da6c28aaSamw } 1410da6c28aaSamw 1411da6c28aaSamw int 14128d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset, 1413da6c28aaSamw unsigned long *sizing_p) 1414da6c28aaSamw { 14158d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 14168d7e4166Sjose borrego unsigned long pdu_offset; 14178d7e4166Sjose borrego int rc; 1418da6c28aaSamw 1419da6c28aaSamw pdu_offset = outer_ref->pdu_offset + offset; 1420da6c28aaSamw 14218d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 14228d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 14238d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1424da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1425da6c28aaSamw return (0); 1426da6c28aaSamw } 1427da6c28aaSamw 14288d7e4166Sjose borrego switch (nds->m_op) { 1429da6c28aaSamw case NDR_M_OP_MARSHALL: 14308d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14318d7e4166Sjose borrego nds->swap, outer_ref); 1432da6c28aaSamw break; 1433da6c28aaSamw 1434da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1435da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1436da6c28aaSamw return (0); 1437da6c28aaSamw 1438da6c28aaSamw default: 1439da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1440da6c28aaSamw return (0); 1441da6c28aaSamw } 1442da6c28aaSamw 1443da6c28aaSamw return (rc); 1444da6c28aaSamw } 1445da6c28aaSamw 1446da6c28aaSamw /* 1447da6c28aaSamw * All OUTER constructs begin on a mod4 (dword) boundary - except 1448da6c28aaSamw * for the ones that don't: some MSRPC calls appear to use word or 1449da6c28aaSamw * packed alignment. Strings appear to be dword aligned. 1450da6c28aaSamw */ 1451da6c28aaSamw int 14528d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref) 1453da6c28aaSamw { 14548d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 14558d7e4166Sjose borrego int rc; 14568d7e4166Sjose borrego unsigned n_pad; 14578d7e4166Sjose borrego unsigned align; 1458da6c28aaSamw 1459da6c28aaSamw if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 1460da6c28aaSamw align = outer_ref->ti->alignment; 14618d7e4166Sjose borrego n_pad = ((align + 1) - nds->pdu_scan_offset) & align; 1462da6c28aaSamw } else { 14638d7e4166Sjose borrego n_pad = NDR_ALIGN4(nds->pdu_scan_offset); 1464da6c28aaSamw } 1465da6c28aaSamw 1466da6c28aaSamw if (n_pad == 0) 1467da6c28aaSamw return (1); /* already aligned, often the case */ 1468da6c28aaSamw 14698d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_pad)) 1470da6c28aaSamw return (0); /* error already set */ 1471da6c28aaSamw 14728d7e4166Sjose borrego switch (nds->m_op) { 1473da6c28aaSamw case NDR_M_OP_MARSHALL: 14748d7e4166Sjose borrego rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref); 1475da6c28aaSamw if (!rc) { 1476da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 1477da6c28aaSamw return (0); 1478da6c28aaSamw } 1479da6c28aaSamw break; 1480da6c28aaSamw 1481da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1482da6c28aaSamw break; 1483da6c28aaSamw 1484da6c28aaSamw default: 1485da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1486da6c28aaSamw return (0); 1487da6c28aaSamw } 1488da6c28aaSamw 14898d7e4166Sjose borrego nds->pdu_scan_offset += n_pad; 1490da6c28aaSamw return (1); 1491da6c28aaSamw } 1492da6c28aaSamw 1493da6c28aaSamw int 14948d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total) 1495da6c28aaSamw { 14968d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 14978d7e4166Sjose borrego unsigned long pdu_want_size; 14988d7e4166Sjose borrego int rc, is_ok = 0; 1499da6c28aaSamw 15008d7e4166Sjose borrego pdu_want_size = nds->pdu_scan_offset + n_total; 1501da6c28aaSamw 15028d7e4166Sjose borrego if (pdu_want_size <= nds->pdu_max_size) { 1503da6c28aaSamw is_ok = 1; 1504da6c28aaSamw } 1505da6c28aaSamw 15068d7e4166Sjose borrego switch (nds->m_op) { 1507da6c28aaSamw case NDR_M_OP_MARSHALL: 1508da6c28aaSamw if (is_ok) 1509da6c28aaSamw break; 15108d7e4166Sjose borrego rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref); 1511da6c28aaSamw if (!rc) { 1512da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 1513da6c28aaSamw return (0); 1514da6c28aaSamw } 1515da6c28aaSamw break; 1516da6c28aaSamw 1517da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1518da6c28aaSamw if (is_ok) 1519da6c28aaSamw break; 1520da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 1521da6c28aaSamw return (0); 1522da6c28aaSamw 1523da6c28aaSamw default: 1524da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1525da6c28aaSamw return (0); 1526da6c28aaSamw } 1527da6c28aaSamw 15288d7e4166Sjose borrego if (nds->pdu_size < pdu_want_size) 15298d7e4166Sjose borrego nds->pdu_size = pdu_want_size; 1530da6c28aaSamw 1531da6c28aaSamw outer_ref->pdu_end_offset = pdu_want_size; 1532da6c28aaSamw return (1); 1533da6c28aaSamw } 1534da6c28aaSamw 1535da6c28aaSamw /* 1536da6c28aaSamw * INNER ELEMENTS 1537da6c28aaSamw * 1538da6c28aaSamw * The local datum (arg_ref->datum) already exists, there is no need to 1539da6c28aaSamw * malloc() it. The datum should point at a member of a structure. 1540da6c28aaSamw * 15418d7e4166Sjose borrego * For the most part, ndr_inner() and its helpers are just a sanity 1542da6c28aaSamw * check. The underlying ti->ndr_func() could be called immediately 1543da6c28aaSamw * for non-pointer elements. For the sake of robustness, we detect 1544da6c28aaSamw * run-time errors here. Most of the situations this protects against 1545da6c28aaSamw * have already been checked by the IDL compiler. This is also a 1546da6c28aaSamw * common point for processing of all data, and so is a convenient 1547da6c28aaSamw * place to work from for debugging. 1548da6c28aaSamw */ 1549da6c28aaSamw int 15508d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref) 1551da6c28aaSamw { 15528d7e4166Sjose borrego ndr_typeinfo_t *ti = arg_ref->ti; 1553da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 1554da6c28aaSamw int is_union = NDR_IS_UNION(ti); 1555da6c28aaSamw int error = NDR_ERR_INNER_PARAMS_BAD; 1556da6c28aaSamw int params; 1557da6c28aaSamw 1558da6c28aaSamw params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1559da6c28aaSamw 1560da6c28aaSamw switch (params) { 1561da6c28aaSamw case NDR_F_NONE: 1562da6c28aaSamw if (is_union) { 1563da6c28aaSamw error = NDR_ERR_SWITCH_VALUE_MISSING; 1564da6c28aaSamw break; 1565da6c28aaSamw } 1566da6c28aaSamw return (*ti->ndr_func)(arg_ref); 1567da6c28aaSamw 1568da6c28aaSamw case NDR_F_SIZE_IS: 1569da6c28aaSamw case NDR_F_DIMENSION_IS: 1570da6c28aaSamw case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 1571da6c28aaSamw case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 1572da6c28aaSamw if (is_varlen) { 1573da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 1574da6c28aaSamw break; 1575da6c28aaSamw } 1576da6c28aaSamw if (is_union) { 1577da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1578da6c28aaSamw break; 1579da6c28aaSamw } 1580da6c28aaSamw if (params & NDR_F_IS_POINTER) 15818d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1582da6c28aaSamw else if (params & NDR_F_IS_REFERENCE) 15838d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1584da6c28aaSamw else 15858d7e4166Sjose borrego return (ndr_inner_array(arg_ref)); 1586da6c28aaSamw 1587da6c28aaSamw case NDR_F_IS_POINTER: /* type is pointer to one something */ 1588da6c28aaSamw if (is_union) { 1589da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1590da6c28aaSamw break; 1591da6c28aaSamw } 15928d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1593da6c28aaSamw 1594da6c28aaSamw case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 1595da6c28aaSamw if (is_union) { 1596da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1597da6c28aaSamw break; 1598da6c28aaSamw } 15998d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1600da6c28aaSamw 1601da6c28aaSamw case NDR_F_SWITCH_IS: 1602da6c28aaSamw if (!is_union) { 1603da6c28aaSamw error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 1604da6c28aaSamw break; 1605da6c28aaSamw } 1606da6c28aaSamw return (*ti->ndr_func)(arg_ref); 1607da6c28aaSamw 1608da6c28aaSamw default: 1609da6c28aaSamw error = NDR_ERR_INNER_PARAMS_BAD; 1610da6c28aaSamw break; 1611da6c28aaSamw } 1612da6c28aaSamw 1613da6c28aaSamw /* 1614da6c28aaSamw * If we get here, something is wrong. Most likely, 1615da6c28aaSamw * the params flags do not match 1616da6c28aaSamw */ 1617da6c28aaSamw NDR_SET_ERROR(arg_ref, error); 1618da6c28aaSamw return (0); 1619da6c28aaSamw } 1620da6c28aaSamw 1621da6c28aaSamw int 16228d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref) 1623da6c28aaSamw { 16248d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1625da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16268d7e4166Sjose borrego char **valpp = (char **)arg_ref->datum; 16278d7e4166Sjose borrego ndr_ref_t *outer_ref; 1628da6c28aaSamw 16298d7e4166Sjose borrego if (!ndr__ulong(arg_ref)) 1630da6c28aaSamw return (0); /* error */ 1631da6c28aaSamw if (!*valpp) 1632da6c28aaSamw return (1); /* NULL pointer */ 1633da6c28aaSamw 16348d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1635da6c28aaSamw if (!outer_ref) 1636da6c28aaSamw return (0); /* error already set */ 1637da6c28aaSamw 1638f96bd5c8SAlan Wright /* 1639f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1640f96bd5c8SAlan Wright * Retain pointer flag for conformant arrays. 1641f96bd5c8SAlan Wright */ 1642da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1643f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1644f96bd5c8SAlan Wright outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 1645f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET 1646da6c28aaSamw outer_ref->outer_flags |= NDR_F_BACKPTR; 1647da6c28aaSamw if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1648da6c28aaSamw outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1649da6c28aaSamw } 1650f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */ 1651da6c28aaSamw 1652da6c28aaSamw outer_ref->backptr = valpp; 1653da6c28aaSamw 16548d7e4166Sjose borrego switch (nds->m_op) { 1655da6c28aaSamw case NDR_M_OP_MARSHALL: 1656da6c28aaSamw outer_ref->datum = *valpp; 1657da6c28aaSamw break; 1658da6c28aaSamw 1659da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1660da6c28aaSamw /* 1661da6c28aaSamw * This is probably wrong if the application allocated 1662da6c28aaSamw * memory in advance. Indicate no value for now. 1663da6c28aaSamw * ONC RPC handles this case. 1664da6c28aaSamw */ 1665da6c28aaSamw *valpp = 0; 1666da6c28aaSamw outer_ref->datum = 0; 1667da6c28aaSamw break; 1668da6c28aaSamw } 1669da6c28aaSamw 1670da6c28aaSamw return (1); /* pointer dereference scheduled */ 1671da6c28aaSamw } 1672da6c28aaSamw 1673da6c28aaSamw int 16748d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref) 1675da6c28aaSamw { 16768d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1677da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16788d7e4166Sjose borrego char **valpp = (char **)arg_ref->datum; 16798d7e4166Sjose borrego ndr_ref_t *outer_ref; 1680da6c28aaSamw 16818d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1682da6c28aaSamw if (!outer_ref) 1683da6c28aaSamw return (0); /* error already set */ 1684da6c28aaSamw 1685f96bd5c8SAlan Wright /* 1686f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1687f96bd5c8SAlan Wright * Retain reference flag for conformant arrays. 1688f96bd5c8SAlan Wright */ 1689da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1690f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1691f96bd5c8SAlan Wright outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 1692da6c28aaSamw #ifdef NDR_INNER_REF_NOT_YET 1693da6c28aaSamw outer_ref->outer_flags |= NDR_F_BACKPTR; 1694da6c28aaSamw if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1695da6c28aaSamw outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1696da6c28aaSamw } 1697da6c28aaSamw #endif /* NDR_INNER_REF_NOT_YET */ 1698da6c28aaSamw 1699da6c28aaSamw outer_ref->backptr = valpp; 1700da6c28aaSamw 17018d7e4166Sjose borrego switch (nds->m_op) { 1702da6c28aaSamw case NDR_M_OP_MARSHALL: 1703da6c28aaSamw outer_ref->datum = *valpp; 1704da6c28aaSamw break; 1705da6c28aaSamw 1706da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1707da6c28aaSamw /* 1708da6c28aaSamw * This is probably wrong if the application allocated 1709da6c28aaSamw * memory in advance. Indicate no value for now. 1710da6c28aaSamw * ONC RPC handles this case. 1711da6c28aaSamw */ 1712da6c28aaSamw *valpp = 0; 1713da6c28aaSamw outer_ref->datum = 0; 1714da6c28aaSamw break; 1715da6c28aaSamw } 1716da6c28aaSamw 1717da6c28aaSamw return (1); /* pointer dereference scheduled */ 1718da6c28aaSamw } 1719da6c28aaSamw 1720da6c28aaSamw int 17218d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref) 1722da6c28aaSamw { 17238d7e4166Sjose borrego ndr_typeinfo_t *ti = encl_ref->ti; 17248d7e4166Sjose borrego ndr_ref_t myref; 1725da6c28aaSamw unsigned long pdu_offset = encl_ref->pdu_offset; 1726da6c28aaSamw unsigned long n_elem; 1727da6c28aaSamw unsigned long i; 1728da6c28aaSamw char name[30]; 1729da6c28aaSamw 1730da6c28aaSamw if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 1731da6c28aaSamw /* now is the time to check/set size */ 17328d7e4166Sjose borrego if (!ndr_size_is(encl_ref)) 1733da6c28aaSamw return (0); /* error already set */ 1734da6c28aaSamw n_elem = encl_ref->size_is; 1735da6c28aaSamw } else { 1736da6c28aaSamw assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 1737da6c28aaSamw n_elem = encl_ref->dimension_is; 1738da6c28aaSamw } 1739da6c28aaSamw 1740da6c28aaSamw bzero(&myref, sizeof (myref)); 1741da6c28aaSamw myref.enclosing = encl_ref; 1742da6c28aaSamw myref.stream = encl_ref->stream; 1743da6c28aaSamw myref.packed_alignment = 0; 1744da6c28aaSamw myref.ti = ti; 1745da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1746da6c28aaSamw 1747da6c28aaSamw for (i = 0; i < n_elem; i++) { 17483299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 1749da6c28aaSamw myref.name = name; 1750da6c28aaSamw myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 1751da6c28aaSamw myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 1752da6c28aaSamw 17538d7e4166Sjose borrego if (!ndr_inner(&myref)) 1754da6c28aaSamw return (0); 1755da6c28aaSamw } 1756da6c28aaSamw 1757da6c28aaSamw return (1); 1758da6c28aaSamw } 1759da6c28aaSamw 1760da6c28aaSamw 1761da6c28aaSamw /* 1762da6c28aaSamw * BASIC TYPES 1763da6c28aaSamw */ 1764da6c28aaSamw #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17658d7e4166Sjose borrego extern int ndr_##TYPE(struct ndr_reference *encl_ref); \ 17668d7e4166Sjose borrego ndr_typeinfo_t ndt_##TYPE = { \ 1767da6c28aaSamw 1, /* NDR version */ \ 1768da6c28aaSamw (SIZE)-1, /* alignment */ \ 1769da6c28aaSamw NDR_F_NONE, /* flags */ \ 17708d7e4166Sjose borrego ndr_##TYPE, /* ndr_func */ \ 1771da6c28aaSamw SIZE, /* pdu_size_fixed_part */ \ 1772da6c28aaSamw 0, /* pdu_size_variable_part */ \ 1773da6c28aaSamw SIZE, /* c_size_fixed_part */ \ 1774da6c28aaSamw 0, /* c_size_variable_part */ \ 1775da6c28aaSamw }; \ 17768d7e4166Sjose borrego int ndr_##TYPE(struct ndr_reference *ref) { \ 17778d7e4166Sjose borrego return (ndr_basic_integer(ref, SIZE)); \ 1778da6c28aaSamw } 1779da6c28aaSamw 1780da6c28aaSamw #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 17818d7e4166Sjose borrego extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \ 17828d7e4166Sjose borrego ndr_typeinfo_t ndt_s##TYPE = { \ 1783da6c28aaSamw 1, /* NDR version */ \ 1784da6c28aaSamw (SIZE)-1, /* alignment */ \ 1785da6c28aaSamw NDR_F_STRING, /* flags */ \ 17868d7e4166Sjose borrego ndr_s##TYPE, /* ndr_func */ \ 1787da6c28aaSamw 0, /* pdu_size_fixed_part */ \ 1788da6c28aaSamw SIZE, /* pdu_size_variable_part */ \ 1789da6c28aaSamw 0, /* c_size_fixed_part */ \ 1790da6c28aaSamw SIZE, /* c_size_variable_part */ \ 1791da6c28aaSamw }; \ 17928d7e4166Sjose borrego int ndr_s##TYPE(struct ndr_reference *ref) { \ 17938d7e4166Sjose borrego return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \ 1794da6c28aaSamw } 1795da6c28aaSamw 1796da6c28aaSamw #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 1797da6c28aaSamw MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1798da6c28aaSamw MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 1799da6c28aaSamw 18008d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned); 18018d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *); 1802da6c28aaSamw 18033299f39fSGordon Ross /* Comments to be nice to those searching for these types. */ 18043299f39fSGordon Ross MAKE_BASIC_TYPE(_char, 1) /* ndt__char, ndt_s_char */ 18053299f39fSGordon Ross MAKE_BASIC_TYPE(_uchar, 1) /* ndt__uchar, ndt_s_uchar */ 18063299f39fSGordon Ross MAKE_BASIC_TYPE(_short, 2) /* ndt__short, ndt_s_short */ 18073299f39fSGordon Ross MAKE_BASIC_TYPE(_ushort, 2) /* ndt__ushort, ndt_s_ushort */ 18083299f39fSGordon Ross MAKE_BASIC_TYPE(_long, 4) /* ndt__long, ndt_s_long */ 18093299f39fSGordon Ross MAKE_BASIC_TYPE(_ulong, 4) /* ndt__ulong, ndt_s_ulong */ 1810da6c28aaSamw 18113299f39fSGordon Ross MAKE_BASIC_TYPE_BASE(_wchar, 2) /* ndt__wchar, ndt_s_wchar */ 1812da6c28aaSamw 1813da6c28aaSamw int 18148d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size) 1815da6c28aaSamw { 18163299f39fSGordon Ross ndr_stream_t *nds = ref->stream; 18178d7e4166Sjose borrego char *valp = (char *)ref->datum; 18188d7e4166Sjose borrego int rc; 1819da6c28aaSamw 18208d7e4166Sjose borrego switch (nds->m_op) { 1821da6c28aaSamw case NDR_M_OP_MARSHALL: 18228d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, ref->pdu_offset, size, 18238d7e4166Sjose borrego valp, nds->swap, ref); 1824da6c28aaSamw break; 1825da6c28aaSamw 1826da6c28aaSamw case NDR_M_OP_UNMARSHALL: 18278d7e4166Sjose borrego rc = NDS_GET_PDU(nds, ref->pdu_offset, size, 18288d7e4166Sjose borrego valp, nds->swap, ref); 1829da6c28aaSamw break; 1830da6c28aaSamw 1831da6c28aaSamw default: 1832da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 1833da6c28aaSamw return (0); 1834da6c28aaSamw } 1835da6c28aaSamw 1836da6c28aaSamw return (rc); 1837da6c28aaSamw } 1838da6c28aaSamw 1839da6c28aaSamw int 18408d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under) 1841da6c28aaSamw { 1842da6c28aaSamw unsigned long pdu_offset = encl_ref->pdu_offset; 1843da6c28aaSamw unsigned size = type_under->pdu_size_fixed_part; 1844da6c28aaSamw char *valp; 18458d7e4166Sjose borrego ndr_ref_t myref; 1846da6c28aaSamw unsigned long i; 1847da6c28aaSamw long sense = 0; 1848da6c28aaSamw char name[30]; 1849da6c28aaSamw 1850da6c28aaSamw assert(size != 0); 1851da6c28aaSamw 1852da6c28aaSamw bzero(&myref, sizeof (myref)); 1853da6c28aaSamw myref.enclosing = encl_ref; 1854da6c28aaSamw myref.stream = encl_ref->stream; 1855da6c28aaSamw myref.packed_alignment = 0; 1856da6c28aaSamw myref.ti = type_under; 1857da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1858da6c28aaSamw myref.name = name; 1859da6c28aaSamw 1860da6c28aaSamw for (i = 0; i < NDR_STRING_MAX; i++) { 18613299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 1862da6c28aaSamw myref.pdu_offset = pdu_offset + i * size; 1863da6c28aaSamw valp = encl_ref->datum + i * size; 1864da6c28aaSamw myref.datum = valp; 1865da6c28aaSamw 18668d7e4166Sjose borrego if (!ndr_inner(&myref)) 1867da6c28aaSamw return (0); 1868da6c28aaSamw 1869da6c28aaSamw switch (size) { 1870da6c28aaSamw case 1: sense = *valp; break; 1871da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1872da6c28aaSamw case 2: sense = *(short *)valp; break; 1873da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1874da6c28aaSamw case 4: sense = *(long *)valp; break; 1875da6c28aaSamw } 1876da6c28aaSamw 1877da6c28aaSamw if (!sense) 1878da6c28aaSamw break; 1879da6c28aaSamw } 1880da6c28aaSamw 1881da6c28aaSamw return (1); 1882da6c28aaSamw } 1883da6c28aaSamw 1884da6c28aaSamw 18858d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref); 18868d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = { 1887da6c28aaSamw 1, /* NDR version */ 1888da6c28aaSamw 2-1, /* alignment */ 1889da6c28aaSamw NDR_F_STRING, /* flags */ 18908d7e4166Sjose borrego ndr_s_wchar, /* ndr_func */ 1891da6c28aaSamw 0, /* pdu_size_fixed_part */ 1892da6c28aaSamw 2, /* pdu_size_variable_part */ 1893da6c28aaSamw 0, /* c_size_fixed_part */ 1894da6c28aaSamw 1, /* c_size_variable_part */ 1895da6c28aaSamw }; 1896da6c28aaSamw 1897da6c28aaSamw 1898da6c28aaSamw /* 1899da6c28aaSamw * Hand coded wchar function because all strings are transported 1900da6c28aaSamw * as wide characters. During NDR_M_OP_MARSHALL, we convert from 1901da6c28aaSamw * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 1902da6c28aaSamw * convert from wide characters to multi-byte. 1903da6c28aaSamw * 19043299f39fSGordon Ross * The most critical thing to get right in this function is to 19053299f39fSGordon Ross * marshall or unmarshall _exactly_ the number of elements the 19063299f39fSGordon Ross * OtW length specifies, as saved by the caller in: strlen_is. 19073299f39fSGordon Ross * Doing otherwise would leave us positioned at the wrong place 19083299f39fSGordon Ross * in the data stream for whatever follows this. Note that the 19093299f39fSGordon Ross * string data covered by strlen_is may or may not include any 19103299f39fSGordon Ross * null termination, but the converted string provided by the 19113299f39fSGordon Ross * caller or returned always has a null terminator. 1912da6c28aaSamw */ 1913da6c28aaSamw int 19148d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref) 1915da6c28aaSamw { 19168d7e4166Sjose borrego ndr_stream_t *nds = encl_ref->stream; 19173299f39fSGordon Ross char *valp = encl_ref->datum; 19188d7e4166Sjose borrego ndr_ref_t myref; 1919da6c28aaSamw char name[30]; 19203299f39fSGordon Ross ndr_wchar_t wcs[NDR_STRING_MAX+1]; 19213299f39fSGordon Ross size_t i, slen, wlen; 19223299f39fSGordon Ross 19233299f39fSGordon Ross /* This is enforced in ndr_outer_string() */ 19243299f39fSGordon Ross assert(encl_ref->strlen_is <= NDR_STRING_MAX); 1925da6c28aaSamw 19268d7e4166Sjose borrego if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1927da6c28aaSamw /* 1928da6c28aaSamw * To avoid problems with zero length strings 1929da6c28aaSamw * we can just null terminate here and be done. 1930da6c28aaSamw */ 1931da6c28aaSamw if (encl_ref->strlen_is == 0) { 1932da6c28aaSamw encl_ref->datum[0] = '\0'; 1933da6c28aaSamw return (1); 1934da6c28aaSamw } 1935da6c28aaSamw } 1936da6c28aaSamw 19373299f39fSGordon Ross /* 19383299f39fSGordon Ross * If we're marshalling, convert the given string 19393299f39fSGordon Ross * from UTF-8 into a local UCS-2 string. 19403299f39fSGordon Ross */ 19413299f39fSGordon Ross if (nds->m_op == NDR_M_OP_MARSHALL) { 19423299f39fSGordon Ross wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX); 19433299f39fSGordon Ross if (wlen == (size_t)-1) 19443299f39fSGordon Ross return (0); 19453299f39fSGordon Ross /* 19463299f39fSGordon Ross * Add a nulls to make strlen_is. 19473299f39fSGordon Ross * (always zero or one of them) 19483299f39fSGordon Ross * Then null terminate at wlen, 19493299f39fSGordon Ross * just for debug convenience. 19503299f39fSGordon Ross */ 19513299f39fSGordon Ross while (wlen < encl_ref->strlen_is) 19523299f39fSGordon Ross wcs[wlen++] = 0; 19533299f39fSGordon Ross wcs[wlen] = 0; 19543299f39fSGordon Ross } 19553299f39fSGordon Ross 19563299f39fSGordon Ross /* 19573299f39fSGordon Ross * Copy wire data to or from the local wc string. 19583299f39fSGordon Ross * Always exactly strlen_is elements. 19593299f39fSGordon Ross */ 1960da6c28aaSamw bzero(&myref, sizeof (myref)); 1961da6c28aaSamw myref.enclosing = encl_ref; 1962da6c28aaSamw myref.stream = encl_ref->stream; 1963da6c28aaSamw myref.packed_alignment = 0; 1964da6c28aaSamw myref.ti = &ndt__wchar; 1965da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1966da6c28aaSamw myref.name = name; 1967da6c28aaSamw myref.pdu_offset = encl_ref->pdu_offset; 19683299f39fSGordon Ross myref.datum = (char *)wcs; 19693299f39fSGordon Ross wlen = encl_ref->strlen_is; 1970da6c28aaSamw 19713299f39fSGordon Ross for (i = 0; i < wlen; i++) { 19723299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 19738d7e4166Sjose borrego if (!ndr_inner(&myref)) 1974da6c28aaSamw return (0); 19753299f39fSGordon Ross myref.pdu_offset += sizeof (ndr_wchar_t); 19763299f39fSGordon Ross myref.datum += sizeof (ndr_wchar_t); 19773299f39fSGordon Ross } 1978da6c28aaSamw 19793299f39fSGordon Ross /* 19803299f39fSGordon Ross * If this is unmarshall, convert the local UCS-2 string 19813299f39fSGordon Ross * into a UTF-8 string in the caller's buffer. The caller 19823299f39fSGordon Ross * previously determined the space required and provides a 19833299f39fSGordon Ross * buffer of sufficient size. 19843299f39fSGordon Ross */ 19853299f39fSGordon Ross if (nds->m_op == NDR_M_OP_UNMARSHALL) { 19863299f39fSGordon Ross wcs[wlen] = 0; 1987*d1855c81SGordon Ross slen = encl_ref->size_is * NDR_MB_CHAR_MAX; 1988*d1855c81SGordon Ross slen = ndr__wcstombs(valp, wcs, slen); 19893299f39fSGordon Ross if (slen == (size_t)-1) 19903299f39fSGordon Ross return (0); 19913299f39fSGordon Ross valp[slen] = '\0'; 1992da6c28aaSamw } 1993da6c28aaSamw 1994da6c28aaSamw return (1); 1995da6c28aaSamw } 199655bf511dSas 199755bf511dSas /* 199855bf511dSas * Converts a multibyte character string to a little-endian, wide-char 199955bf511dSas * string. No more than nwchars wide characters are stored. 200055bf511dSas * A terminating null wide character is appended if there is room. 200155bf511dSas * 200255bf511dSas * Returns the number of wide characters converted, not counting 200355bf511dSas * any terminating null wide character. Returns -1 if an invalid 200455bf511dSas * multibyte character is encountered. 200555bf511dSas */ 20063299f39fSGordon Ross /* ARGSUSED */ 200755bf511dSas size_t 20083299f39fSGordon Ross ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs, 200955bf511dSas size_t nwchars) 201055bf511dSas { 20113299f39fSGordon Ross size_t len; 201255bf511dSas 201355bf511dSas #ifdef _BIG_ENDIAN 20143299f39fSGordon Ross if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) { 20153299f39fSGordon Ross /* Make WC string in LE order. */ 20163299f39fSGordon Ross len = ndr__mbstowcs_le(wcs, mbs, nwchars); 20173299f39fSGordon Ross } else 201855bf511dSas #endif 20193299f39fSGordon Ross len = ndr__mbstowcs(wcs, mbs, nwchars); 202055bf511dSas 20213299f39fSGordon Ross return (len); 202255bf511dSas } 2023