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. 24*1ca4e8dfSGordon Ross * 2533f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 26*1ca4e8dfSGordon Ross * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. 27da6c28aaSamw */ 28da6c28aaSamw 29da6c28aaSamw /* 30da6c28aaSamw * Network Data Representation (NDR) is a compatible subset of the DCE RPC 31da6c28aaSamw * and MSRPC NDR. NDR is used to move parameters consisting of 32da6c28aaSamw * complicated trees of data constructs between an RPC client and server. 33da6c28aaSamw */ 34da6c28aaSamw 3555bf511dSas #include <sys/byteorder.h> 36da6c28aaSamw #include <strings.h> 37da6c28aaSamw #include <assert.h> 38da6c28aaSamw #include <string.h> 393299f39fSGordon Ross #include <stdio.h> 40da6c28aaSamw #include <stdlib.h> 41da6c28aaSamw 423299f39fSGordon Ross #include <libmlrpc.h> 433299f39fSGordon Ross #include <ndr_wchar.h> 44da6c28aaSamw 45da6c28aaSamw #define NDR_IS_UNION(T) \ 46da6c28aaSamw (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION) 47da6c28aaSamw #define NDR_IS_STRING(T) \ 48da6c28aaSamw (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING) 49da6c28aaSamw 508d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar; 51da6c28aaSamw 52da6c28aaSamw /* 53da6c28aaSamw * The following synopsis describes the terms TOP-MOST, OUTER and INNER. 54da6c28aaSamw * 55da6c28aaSamw * Each parameter (call arguments and return values) is a TOP-MOST item. 56da6c28aaSamw * A TOP-MOST item consists of one or more OUTER items. An OUTER item 57da6c28aaSamw * consists of one or more INNER items. There are important differences 58da6c28aaSamw * between each kind, which, primarily, have to do with the allocation 59da6c28aaSamw * of memory to contain data structures and the order of processing. 60da6c28aaSamw * 61da6c28aaSamw * This is most easily demonstrated with a short example. 62da6c28aaSamw * Consider these structures: 63da6c28aaSamw * 64da6c28aaSamw * struct top_param { 65da6c28aaSamw * long level; 66da6c28aaSamw * struct list * head; 67da6c28aaSamw * long count; 68da6c28aaSamw * }; 69da6c28aaSamw * 70da6c28aaSamw * struct list { 71da6c28aaSamw * struct list * next; 72da6c28aaSamw * char * str; // a string 73da6c28aaSamw * }; 74da6c28aaSamw * 75da6c28aaSamw * Now, consider an instance tree like this: 76da6c28aaSamw * 77da6c28aaSamw * +---------+ +-------+ +-------+ 78da6c28aaSamw * |top_param| +--->|list #1| +--->|list #2| 79da6c28aaSamw * +---------+ | +-------+ | +-------+ 80da6c28aaSamw * | level | | | next ----+ | next --->(NULL) 81da6c28aaSamw * | head ----+ | str -->"foo" | str -->"bar" 82da6c28aaSamw * | count | | flag | | flag | 83da6c28aaSamw * +---------+ +-------+ +-------+ 84da6c28aaSamw * 85da6c28aaSamw * The DCE(MS)/RPC Stub Data encoding for the tree is the following. 86da6c28aaSamw * The vertical bars (|) indicate OUTER construct boundaries. 87da6c28aaSamw * 88da6c28aaSamw * +-----+----------------------+----------------------+-----+-----+-----+ 89da6c28aaSamw * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count| 90da6c28aaSamw * +-----+----------------------+----------------------+-----+-----+-----+ 91da6c28aaSamw * level |<----------------------- head -------------------------->|count 92da6c28aaSamw * TOP TOP TOP 93da6c28aaSamw * 94da6c28aaSamw * Here's what to notice: 95da6c28aaSamw * 96da6c28aaSamw * - The members of the TOP-MOST construct are scattered through the Stub 97da6c28aaSamw * Data in the order they occur. This example shows a TOP-MOST construct 98da6c28aaSamw * consisting of atomic types (pointers and integers). A construct 99da6c28aaSamw * (struct) within the TOP-MOST construct would be contiguous and not 100da6c28aaSamw * scattered. 101da6c28aaSamw * 102da6c28aaSamw * - The members of OUTER constructs are contiguous, which allows for 103da6c28aaSamw * non-copied relocated (fixed-up) data structures at the packet's 104da6c28aaSamw * destination. We don't do fix-ups here. The pointers within the 105da6c28aaSamw * OUTER constructs are processed depth-first in the order that they 106da6c28aaSamw * occur. If they were processed breadth first, the sequence would 107da6c28aaSamw * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may 108da6c28aaSamw * be variable length, and pointers are often encountered before the 109da6c28aaSamw * size(s) is known. 110da6c28aaSamw * 111da6c28aaSamw * - The INNER constructs are simply the members of an OUTER construct. 112da6c28aaSamw * 113da6c28aaSamw * For comparison, consider how ONC RPC would handle the same tree of 114da6c28aaSamw * data. ONC requires very little buffering, while DCE requires enough 115da6c28aaSamw * buffer space for the entire message. ONC does atom-by-atom depth-first 116da6c28aaSamw * (de)serialization and copy, while DCE allows for constructs to be 117da6c28aaSamw * "fixed-up" (relocated) in place at the destination. The packet data 118da6c28aaSamw * for the same tree processed by ONC RPC would look like this: 119da6c28aaSamw * 120da6c28aaSamw * +---------------------------------------------------------------------+ 121da6c28aaSamw * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count| 122da6c28aaSamw * +---------------------------------------------------------------------+ 123da6c28aaSamw * TOP #1 #2 #2 bar #2 #1 foo #1 TOP 124da6c28aaSamw * 125da6c28aaSamw * More details about each TOP-MOST, OUTER, and INNER constructs appear 126da6c28aaSamw * throughout this source file near where such constructs are processed. 127da6c28aaSamw * 128da6c28aaSamw * NDR_REFERENCE 129da6c28aaSamw * 1308d7e4166Sjose borrego * The primary object for NDR is the ndr_ref_t. 131da6c28aaSamw * 1328d7e4166Sjose borrego * An ndr reference indicates the local datum (i.e. native "C" data 133da6c28aaSamw * format), and the element within the Stub Data (contained within the 1348d7e4166Sjose borrego * RPC PDU (protocol data unit). An ndr reference also indicates, 135da6c28aaSamw * largely as a debugging aid, something about the type of the 136da6c28aaSamw * element/datum, and the enclosing construct for the element. The 1378d7e4166Sjose borrego * ndr reference's are typically allocated on the stack as locals, 1388d7e4166Sjose borrego * and the chain of ndr-reference.enclosing references is in reverse 139da6c28aaSamw * order of the call graph. 140da6c28aaSamw * 1418d7e4166Sjose borrego * The ndr-reference.datum is a pointer to the local memory that 1428d7e4166Sjose borrego * contains/receives the value. The ndr-reference.pdu_offset indicates 143da6c28aaSamw * where in the Stub Data the value is to be stored/retrieved. 144da6c28aaSamw * 1458d7e4166Sjose borrego * The ndr-reference also contains various parameters to the NDR 1468d7e4166Sjose borrego * process, such as ndr-reference.size_is, which indicates the size 1478d7e4166Sjose borrego * of variable length data, or ndr-reference.switch_is, which 148da6c28aaSamw * indicates the arm of a union to use. 149da6c28aaSamw * 150da6c28aaSamw * QUEUE OF OUTER REFERENCES 151da6c28aaSamw * 152da6c28aaSamw * Some OUTER constructs are variable size. Sometimes (often) we don't 153da6c28aaSamw * know the size of the OUTER construct until after pointers have been 154da6c28aaSamw * encountered. Hence, we can not begin processing the referent of the 155da6c28aaSamw * pointer until after the referring OUTER construct is completely 156da6c28aaSamw * processed, i.e. we don't know where to find/put the referent in the 157da6c28aaSamw * Stub Data until we know the size of all its predecessors. 158da6c28aaSamw * 159da6c28aaSamw * This is managed using the queue of OUTER references. The queue is 1608d7e4166Sjose borrego * anchored in ndr_stream.outer_queue_head. At any time, 1618d7e4166Sjose borrego * ndr_stream.outer_queue_tailp indicates where to put the 1628d7e4166Sjose borrego * ndr-reference for the next encountered pointer. 163da6c28aaSamw * 164da6c28aaSamw * Refer to the example above as we illustrate the queue here. In these 165da6c28aaSamw * illustrations, the queue entries are not the data structures themselves. 1668d7e4166Sjose borrego * Rather, they are ndr-reference entries which **refer** to the data 167da6c28aaSamw * structures in both the PDU and local memory. 168da6c28aaSamw * 169da6c28aaSamw * During some point in the processing, the queue looks like this: 170da6c28aaSamw * 171da6c28aaSamw * outer_current -------v 172da6c28aaSamw * outer_queue_head --> list#1 --0 173da6c28aaSamw * outer_queue_tailp ---------& 174da6c28aaSamw * 175da6c28aaSamw * When the pointer #1.next is encountered, and entry is added to the 176da6c28aaSamw * queue, 177da6c28aaSamw * 178da6c28aaSamw * outer_current -------v 179da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --0 180da6c28aaSamw * outer_queue_tailp --------------------& 181da6c28aaSamw * 182da6c28aaSamw * and the members of #1 continue to be processed, which encounters 183da6c28aaSamw * #1.str: 184da6c28aaSamw * 185da6c28aaSamw * outer_current -------v 186da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "foo" --0 187da6c28aaSamw * outer_queue_tailp ------------------------------& 188da6c28aaSamw * 1898d7e4166Sjose borrego * Upon the completion of list#1, the processing continues by moving to 1908d7e4166Sjose borrego * ndr_stream.outer_current->next, and the tail is set to this outer member: 191da6c28aaSamw * 192da6c28aaSamw * outer_current ------------------v 193da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "foo" --0 194da6c28aaSamw * outer_queue_tailp --------------------& 195da6c28aaSamw * 196da6c28aaSamw * Space for list#2 is allocated, either in the Stub Data or of local 197da6c28aaSamw * memory. When #2.next is encountered, it is found to be the null 198da6c28aaSamw * pointer and no reference is added to the queue. When #2.str is 199da6c28aaSamw * encountered, it is found to be valid, and a reference is added: 200da6c28aaSamw * 201da6c28aaSamw * outer_current ------------------v 202da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 203da6c28aaSamw * outer_queue_tailp ------------------------------& 204da6c28aaSamw * 205da6c28aaSamw * Processing continues in a similar fashion with the string "bar", 206da6c28aaSamw * which is variable-length. At this point, memory for "bar" may be 207da6c28aaSamw * malloc()ed during NDR_M_OP_UNMARSHALL: 208da6c28aaSamw * 209da6c28aaSamw * outer_current -----------------------------v 210da6c28aaSamw * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 211da6c28aaSamw * outer_queue_tailp ------------------------------& 212da6c28aaSamw * 213da6c28aaSamw * And finishes on string "foo". Notice that because "bar" is a 214da6c28aaSamw * variable length string, and we don't know the PDU offset for "foo" 215da6c28aaSamw * until we reach this point. 216da6c28aaSamw * 217da6c28aaSamw * When the queue is drained (current->next==0), processing continues 218da6c28aaSamw * with the next TOP-MOST member. 219da6c28aaSamw * 220da6c28aaSamw * The queue of OUTER constructs manages the variable-length semantics 221da6c28aaSamw * of OUTER constructs and satisfies the depth-first requirement. 222da6c28aaSamw * We allow the queue to linger until the entire TOP-MOST structure is 223da6c28aaSamw * processed as an aid to debugging. 224da6c28aaSamw */ 225da6c28aaSamw 2268d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *); 2278d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *); 228da6c28aaSamw 229da6c28aaSamw /* 230da6c28aaSamw * TOP-MOST ELEMENTS 231da6c28aaSamw * 232da6c28aaSamw * This is fundamentally the first OUTER construct of the parameter, 233da6c28aaSamw * possibly followed by more OUTER constructs due to pointers. The 234da6c28aaSamw * datum (local memory) for TOP-MOST constructs (structs) is allocated 235da6c28aaSamw * by the caller of NDR. 236da6c28aaSamw * 237da6c28aaSamw * After the element is transferred, the outer_queue is drained. 238da6c28aaSamw * 239da6c28aaSamw * All we have to do is add an entry to the outer_queue for this 240da6c28aaSamw * top-most member, and commence the outer_queue processing. 241da6c28aaSamw */ 242da6c28aaSamw int 2438d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum) 244da6c28aaSamw { 2458d7e4166Sjose borrego ndr_ref_t myref; 246da6c28aaSamw 247da6c28aaSamw bzero(&myref, sizeof (myref)); 2488d7e4166Sjose borrego myref.stream = nds; 249da6c28aaSamw myref.datum = datum; 250da6c28aaSamw myref.name = "PROCESS"; 251da6c28aaSamw myref.ti = ti; 252da6c28aaSamw 2538d7e4166Sjose borrego return (ndr_topmost(&myref)); 254da6c28aaSamw } 255da6c28aaSamw 256da6c28aaSamw int 2578d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum) 258da6c28aaSamw { 2598d7e4166Sjose borrego ndr_ref_t myref; 260da6c28aaSamw 261da6c28aaSamw bzero(&myref, sizeof (myref)); 2628d7e4166Sjose borrego myref.stream = nds; 263da6c28aaSamw myref.datum = datum; 264da6c28aaSamw myref.name = "OPERATION"; 265da6c28aaSamw myref.ti = ti; 266da6c28aaSamw myref.inner_flags = NDR_F_SWITCH_IS; 267da6c28aaSamw myref.switch_is = opnum; 268da6c28aaSamw 269da6c28aaSamw if (ti->type_flags != NDR_F_INTERFACE) { 270da6c28aaSamw NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE); 271da6c28aaSamw return (0); 272da6c28aaSamw } 273da6c28aaSamw 274da6c28aaSamw return ((*ti->ndr_func)(&myref)); 275da6c28aaSamw } 276da6c28aaSamw 277da6c28aaSamw int 2788d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref) 279da6c28aaSamw { 2808d7e4166Sjose borrego ndr_typeinfo_t *ti = params_ref->ti; 281da6c28aaSamw 282da6c28aaSamw if (ti->type_flags == NDR_F_OPERATION) 283da6c28aaSamw return (*ti->ndr_func) (params_ref); 284da6c28aaSamw else 2858d7e4166Sjose borrego return (ndr_topmost(params_ref)); 286da6c28aaSamw } 287da6c28aaSamw 288da6c28aaSamw int 2898d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref) 290da6c28aaSamw { 2918d7e4166Sjose borrego ndr_stream_t *nds; 2928d7e4166Sjose borrego ndr_typeinfo_t *ti; 2938d7e4166Sjose borrego ndr_ref_t *outer_ref = 0; 294da6c28aaSamw int is_varlen; 295da6c28aaSamw int is_string; 296da6c28aaSamw int error; 297da6c28aaSamw int rc; 298da6c28aaSamw unsigned n_fixed; 299da6c28aaSamw int params; 300da6c28aaSamw 301da6c28aaSamw assert(top_ref); 302da6c28aaSamw assert(top_ref->stream); 303da6c28aaSamw assert(top_ref->ti); 304da6c28aaSamw 3058d7e4166Sjose borrego nds = top_ref->stream; 306da6c28aaSamw ti = top_ref->ti; 307da6c28aaSamw 308da6c28aaSamw is_varlen = ti->pdu_size_variable_part; 309da6c28aaSamw is_string = NDR_IS_STRING(ti); 310da6c28aaSamw 3118d7e4166Sjose borrego assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp); 3128d7e4166Sjose borrego assert(!nds->outer_current); 313da6c28aaSamw 314da6c28aaSamw params = top_ref->inner_flags & NDR_F_PARAMS_MASK; 315da6c28aaSamw 316da6c28aaSamw switch (params) { 317da6c28aaSamw case NDR_F_NONE: 318da6c28aaSamw case NDR_F_SWITCH_IS: 319da6c28aaSamw if (is_string || is_varlen) { 320da6c28aaSamw error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 321da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 322da6c28aaSamw return (0); 323da6c28aaSamw } 324da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 325da6c28aaSamw break; 326da6c28aaSamw 327da6c28aaSamw case NDR_F_SIZE_IS: 328da6c28aaSamw error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 329da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 330da6c28aaSamw return (0); 331da6c28aaSamw 332da6c28aaSamw case NDR_F_DIMENSION_IS: 333da6c28aaSamw if (is_varlen) { 334da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 335da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 336da6c28aaSamw return (0); 337da6c28aaSamw } 338da6c28aaSamw n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is; 339da6c28aaSamw break; 340da6c28aaSamw 341da6c28aaSamw case NDR_F_IS_POINTER: 342da6c28aaSamw case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 343da6c28aaSamw n_fixed = 4; 344da6c28aaSamw break; 345da6c28aaSamw 346da6c28aaSamw case NDR_F_IS_REFERENCE: 347da6c28aaSamw case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 348da6c28aaSamw n_fixed = 0; 349da6c28aaSamw break; 350da6c28aaSamw 351da6c28aaSamw default: 352da6c28aaSamw error = NDR_ERR_OUTER_PARAMS_BAD; 353da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 354da6c28aaSamw return (0); 355da6c28aaSamw } 356da6c28aaSamw 3578d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(top_ref); 358da6c28aaSamw if (!outer_ref) 359da6c28aaSamw return (0); /* error already set */ 360da6c28aaSamw 361da6c28aaSamw /* 362da6c28aaSamw * Hand-craft the first OUTER construct and directly call 3638d7e4166Sjose borrego * ndr_inner(). Then, run the outer_queue. We do this 3648d7e4166Sjose borrego * because ndr_outer() wants to malloc() memory for 365da6c28aaSamw * the construct, and we already have the memory. 366da6c28aaSamw */ 367da6c28aaSamw 368da6c28aaSamw /* move the flags, etc, around again, undoes enter_outer_queue() */ 369da6c28aaSamw outer_ref->inner_flags = top_ref->inner_flags; 370da6c28aaSamw outer_ref->outer_flags = 0; 371da6c28aaSamw outer_ref->datum = top_ref->datum; 372da6c28aaSamw 373da6c28aaSamw /* All outer constructs start on a mod4 (longword) boundary */ 3748d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 375da6c28aaSamw return (0); /* error already set */ 376da6c28aaSamw 377da6c28aaSamw /* Regardless of what it is, this is where it starts */ 3788d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 379da6c28aaSamw 3808d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_fixed); 381da6c28aaSamw if (!rc) 382da6c28aaSamw return (0); /* error already set */ 383da6c28aaSamw 384da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed; 385da6c28aaSamw 386da6c28aaSamw /* set-up outer_current, as though run_outer_queue() was doing it */ 3878d7e4166Sjose borrego nds->outer_current = outer_ref; 3888d7e4166Sjose borrego nds->outer_queue_tailp = &nds->outer_current->next; 3898d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 390da6c28aaSamw 391da6c28aaSamw /* do the topmost member */ 3928d7e4166Sjose borrego rc = ndr_inner(outer_ref); 393da6c28aaSamw if (!rc) 394da6c28aaSamw return (0); /* error already set */ 395da6c28aaSamw 3968d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 397da6c28aaSamw 398da6c28aaSamw /* advance, as though run_outer_queue() was doing it */ 3998d7e4166Sjose borrego nds->outer_current = nds->outer_current->next; 4008d7e4166Sjose borrego return (ndr_run_outer_queue(nds)); 401da6c28aaSamw } 402da6c28aaSamw 4038d7e4166Sjose borrego static ndr_ref_t * 4048d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref) 405da6c28aaSamw { 4068d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 4078d7e4166Sjose borrego ndr_ref_t *outer_ref; 408da6c28aaSamw 409da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 4108d7e4166Sjose borrego outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref); 411da6c28aaSamw if (!outer_ref) { 412da6c28aaSamw NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED); 413da6c28aaSamw return (0); 414da6c28aaSamw } 415da6c28aaSamw 416da6c28aaSamw *outer_ref = *arg_ref; 417da6c28aaSamw 418da6c28aaSamw /* move advice in inner_flags to outer_flags */ 419da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 420da6c28aaSamw outer_ref->inner_flags = 0; 4218d7e4166Sjose borrego outer_ref->enclosing = nds->outer_current; 422da6c28aaSamw outer_ref->backptr = 0; 423da6c28aaSamw outer_ref->datum = 0; 424da6c28aaSamw 4258d7e4166Sjose borrego assert(nds->outer_queue_tailp); 426da6c28aaSamw 4278d7e4166Sjose borrego outer_ref->next = *nds->outer_queue_tailp; 4288d7e4166Sjose borrego *nds->outer_queue_tailp = outer_ref; 4298d7e4166Sjose borrego nds->outer_queue_tailp = &outer_ref->next; 430da6c28aaSamw return (outer_ref); 431da6c28aaSamw } 432da6c28aaSamw 433da6c28aaSamw int 4348d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds) 435da6c28aaSamw { 4368d7e4166Sjose borrego while (nds->outer_current) { 4378d7e4166Sjose borrego nds->outer_queue_tailp = &nds->outer_current->next; 438da6c28aaSamw 4398d7e4166Sjose borrego if (!ndr_outer(nds->outer_current)) 440da6c28aaSamw return (0); 441da6c28aaSamw 4428d7e4166Sjose borrego nds->outer_current = nds->outer_current->next; 443da6c28aaSamw } 444da6c28aaSamw 445da6c28aaSamw return (1); 446da6c28aaSamw } 447da6c28aaSamw 448da6c28aaSamw /* 449da6c28aaSamw * OUTER CONSTRUCTS 450da6c28aaSamw * 451da6c28aaSamw * OUTER constructs are where the real work is, which stems from the 452da6c28aaSamw * variable-length potential. 453da6c28aaSamw * 454da6c28aaSamw * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT 455da6c28aaSamw * 456da6c28aaSamw * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT, 457da6c28aaSamw * VARYING, and VARYING/CONFORMANT. 458da6c28aaSamw * 459da6c28aaSamw * What makes this so tough is that the variable-length array may be well 460da6c28aaSamw * encapsulated within the outer construct. Further, because DCE(MS)/RPC 461da6c28aaSamw * tries to keep the constructs contiguous in the data stream, the sizing 462da6c28aaSamw * information precedes the entire OUTER construct. The sizing information 463da6c28aaSamw * must be used at the appropriate time, which can be after many, many, 464da6c28aaSamw * many fixed-length elements. During IDL type analysis, we know in 465da6c28aaSamw * advance constructs that encapsulate variable-length constructs. So, 466da6c28aaSamw * we know when we have a sizing header and when we don't. The actual 467da6c28aaSamw * semantics of the header are largely deferred. 468da6c28aaSamw * 469da6c28aaSamw * Currently, VARYING constructs are not implemented but they are described 470da6c28aaSamw * here in case they have to be implemented in the future. Similarly, 471da6c28aaSamw * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently 472da6c28aaSamw * not implemented. Only one-dimensional, variable-length arrays are 473da6c28aaSamw * supported. 474da6c28aaSamw * 475da6c28aaSamw * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW 476da6c28aaSamw * 477da6c28aaSamw * All variable-length values are arrays. These arrays may be embedded 478da6c28aaSamw * well within another construct. However, a variable-length construct 479da6c28aaSamw * may ONLY appear as the last member of an enclosing construct. Example: 480da6c28aaSamw * 481da6c28aaSamw * struct credentials { 482da6c28aaSamw * ulong uid, gid; 483da6c28aaSamw * ulong n_gids; 484da6c28aaSamw * [size_is(n_gids)] 485da6c28aaSamw * ulong gids[*]; // variable-length. 486da6c28aaSamw * }; 487da6c28aaSamw * 488da6c28aaSamw * CONFORMANT constructs have a dynamic size in local memory and in the 489da6c28aaSamw * PDU. The CONFORMANT quality is indicated by the [size_is()] advice. 490da6c28aaSamw * CONFORMANT constructs have the following header: 491da6c28aaSamw * 492da6c28aaSamw * struct conformant_header { 493da6c28aaSamw * ulong size_is; 494da6c28aaSamw * }; 495da6c28aaSamw * 496da6c28aaSamw * (Multi-dimensional CONFORMANT arrays have a similar header for each 497da6c28aaSamw * dimension - not implemented). 498da6c28aaSamw * 499da6c28aaSamw * Example CONFORMANT construct: 500da6c28aaSamw * 501da6c28aaSamw * struct user { 502da6c28aaSamw * char * name; 503da6c28aaSamw * struct credentials cred; // see above 504da6c28aaSamw * }; 505da6c28aaSamw * 506da6c28aaSamw * Consider the data tree: 507da6c28aaSamw * 508da6c28aaSamw * +--------+ 509da6c28aaSamw * | user | 510da6c28aaSamw * +--------+ 511da6c28aaSamw * | name ----> "fred" (the string is a different OUTER) 512da6c28aaSamw * | uid | 513da6c28aaSamw * | gid | 514da6c28aaSamw * | n_gids | for example, 3 515da6c28aaSamw * | gids[0]| 516da6c28aaSamw * | gids[1]| 517da6c28aaSamw * | gids[2]| 518da6c28aaSamw * +--------+ 519da6c28aaSamw * 520da6c28aaSamw * The OUTER construct in the Stub Data would be: 521da6c28aaSamw * 522da6c28aaSamw * +---+---------+---------------------------------------------+ 523da6c28aaSamw * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]| 524da6c28aaSamw * +---+---------+---------------------------------------------+ 525da6c28aaSamw * szing hdr|user |<-------------- user.cred ------------>| 526da6c28aaSamw * |<--- fixed-size ---->|<----- conformant ---->| 527da6c28aaSamw * 528da6c28aaSamw * The ndr_typeinfo for struct user will have: 529da6c28aaSamw * pdu_fixed_size_part = 16 four long words (name uid gid n_gids) 530da6c28aaSamw * pdu_variable_size_part = 4 per element, sizeof gids[0] 531da6c28aaSamw * 532da6c28aaSamw * VARYING CONSTRUCTS -- NOT IMPLEMENTED 533da6c28aaSamw * 534da6c28aaSamw * VARYING constructs have the following header: 535da6c28aaSamw * 536da6c28aaSamw * struct varying_header { 537da6c28aaSamw * ulong first_is; 538da6c28aaSamw * ulong length_is; 539da6c28aaSamw * }; 540da6c28aaSamw * 541da6c28aaSamw * This indicates which interval of an array is significant. 542da6c28aaSamw * Non-intersecting elements of the array are undefined and usually 543da6c28aaSamw * zero-filled. The first_is parameter for C arrays is always 0 for 544da6c28aaSamw * the first element. 545da6c28aaSamw * 546da6c28aaSamw * N.B. Constructs may contain one CONFORMANT element, which is always 547da6c28aaSamw * last, but may contain many VARYING elements, which can be anywhere. 548da6c28aaSamw * 549da6c28aaSamw * VARYING CONFORMANT constructs have the sizing headers arranged like 550da6c28aaSamw * this: 551da6c28aaSamw * 552da6c28aaSamw * struct conformant_header all_conformant[N_CONFORMANT_DIM]; 553da6c28aaSamw * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS]; 554da6c28aaSamw * 555da6c28aaSamw * The sizing header is immediately followed by the values for the 556da6c28aaSamw * construct. Again, we don't support more than one dimension and 557da6c28aaSamw * we don't support VARYING constructs at this time. 558da6c28aaSamw * 559da6c28aaSamw * A good example of a VARYING/CONFORMANT data structure is the UNIX 560da6c28aaSamw * directory entry: 561da6c28aaSamw * 562da6c28aaSamw * struct dirent { 563da6c28aaSamw * ushort reclen; 564da6c28aaSamw * ushort namlen; 565da6c28aaSamw * ulong inum; 566da6c28aaSamw * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL 567da6c28aaSamw * uchar name[*]; 568da6c28aaSamw * }; 569da6c28aaSamw * 570da6c28aaSamw * 571da6c28aaSamw * STRINGS ARE A SPECIAL CASE 572da6c28aaSamw * 573da6c28aaSamw * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures 574da6c28aaSamw * for strings. This is a simple one-dimensional variable-length array, 575da6c28aaSamw * typically with its last element all zeroes. We handle strings with the 576da6c28aaSamw * header: 577da6c28aaSamw * 578da6c28aaSamw * struct string_header { 579da6c28aaSamw * ulong size_is; 580da6c28aaSamw * ulong first_is; // always 0 581da6c28aaSamw * ulong length_is; // always same as size_is 582da6c28aaSamw * }; 583da6c28aaSamw * 584da6c28aaSamw * If general support for VARYING and VARYING/CONFORMANT mechanisms is 585da6c28aaSamw * implemented, we probably won't need the strings special case. 586da6c28aaSamw */ 587da6c28aaSamw int 5888d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref) 589da6c28aaSamw { 590*1ca4e8dfSGordon Ross ndr_stream_t *nds = outer_ref->stream; 5918d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 592da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 593da6c28aaSamw int is_union = NDR_IS_UNION(ti); 594da6c28aaSamw int is_string = NDR_IS_STRING(ti); 595da6c28aaSamw int error = NDR_ERR_OUTER_PARAMS_BAD; 596da6c28aaSamw int params; 597da6c28aaSamw 598da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 599da6c28aaSamw 600da6c28aaSamw NDR_TATTLE(outer_ref, "--OUTER--"); 601da6c28aaSamw 602da6c28aaSamw /* All outer constructs start on a mod4 (longword) boundary */ 6038d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 604da6c28aaSamw return (0); /* error already set */ 605da6c28aaSamw 606da6c28aaSamw /* Regardless of what it is, this is where it starts */ 6078d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 608da6c28aaSamw 609da6c28aaSamw if (is_union) { 610da6c28aaSamw error = NDR_ERR_OUTER_UNION_ILLEGAL; 611da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 612da6c28aaSamw return (0); 613da6c28aaSamw } 614da6c28aaSamw 615da6c28aaSamw switch (params) { 616da6c28aaSamw case NDR_F_NONE: 617da6c28aaSamw if (is_string) 6188d7e4166Sjose borrego return (ndr_outer_string(outer_ref)); 619da6c28aaSamw if (is_varlen) 6208d7e4166Sjose borrego return (ndr_outer_conformant_construct(outer_ref)); 621da6c28aaSamw 6228d7e4166Sjose borrego return (ndr_outer_fixed(outer_ref)); 623da6c28aaSamw 624da6c28aaSamw case NDR_F_SIZE_IS: 625da6c28aaSamw case NDR_F_DIMENSION_IS: 626f96bd5c8SAlan Wright case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 627f96bd5c8SAlan Wright case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 628da6c28aaSamw if (is_varlen) { 629da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 630da6c28aaSamw break; 631da6c28aaSamw } 632da6c28aaSamw 633f96bd5c8SAlan Wright if (params & NDR_F_SIZE_IS) 6348d7e4166Sjose borrego return (ndr_outer_conformant_array(outer_ref)); 635da6c28aaSamw else 6368d7e4166Sjose borrego return (ndr_outer_fixed_array(outer_ref)); 637da6c28aaSamw 638da6c28aaSamw default: 639da6c28aaSamw error = NDR_ERR_OUTER_PARAMS_BAD; 640da6c28aaSamw break; 641da6c28aaSamw } 642da6c28aaSamw 643da6c28aaSamw /* 644da6c28aaSamw * If we get here, something is wrong. Most likely, 645da6c28aaSamw * the params flags do not match. 646da6c28aaSamw */ 647da6c28aaSamw NDR_SET_ERROR(outer_ref, error); 648da6c28aaSamw return (0); 649da6c28aaSamw } 650da6c28aaSamw 651da6c28aaSamw int 6528d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref) 653da6c28aaSamw { 6548d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 6558d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 6568d7e4166Sjose borrego ndr_ref_t myref; 657*1ca4e8dfSGordon Ross char *valp = NULL; 658da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 659da6c28aaSamw int is_union = NDR_IS_UNION(ti); 660da6c28aaSamw int is_string = NDR_IS_STRING(ti); 661da6c28aaSamw int rc; 662da6c28aaSamw unsigned n_hdr; 663da6c28aaSamw unsigned n_fixed; 664da6c28aaSamw unsigned n_variable; 665da6c28aaSamw unsigned n_alloc; 666da6c28aaSamw unsigned n_pdu_total; 667da6c28aaSamw int params; 668da6c28aaSamw 669da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 670da6c28aaSamw 671da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 672da6c28aaSamw assert(params == NDR_F_NONE); 673da6c28aaSamw 674da6c28aaSamw /* no header for this */ 675da6c28aaSamw n_hdr = 0; 676da6c28aaSamw 677da6c28aaSamw /* fixed part -- exactly one of these */ 678da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 679da6c28aaSamw assert(n_fixed > 0); 680da6c28aaSamw 681da6c28aaSamw /* variable part -- exactly none of these */ 682da6c28aaSamw n_variable = 0; 683da6c28aaSamw 684da6c28aaSamw /* sum them up to determine the PDU space required */ 685da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 686da6c28aaSamw 687da6c28aaSamw /* similar sum to determine how much local memory is required */ 688da6c28aaSamw n_alloc = n_fixed + n_variable; 689da6c28aaSamw 6908d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 691da6c28aaSamw if (!rc) 692da6c28aaSamw return (rc); /* error already set */ 693da6c28aaSamw 6948d7e4166Sjose borrego switch (nds->m_op) { 695da6c28aaSamw case NDR_M_OP_MARSHALL: 696da6c28aaSamw valp = outer_ref->datum; 69796a62adaSjoyce mcintosh if (!valp) { 69896a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 69996a62adaSjoyce mcintosh return (0); 70096a62adaSjoyce mcintosh } 701f96bd5c8SAlan Wright if (outer_ref->backptr) 702da6c28aaSamw assert(valp == *outer_ref->backptr); 703da6c28aaSamw break; 704da6c28aaSamw 705da6c28aaSamw case NDR_M_OP_UNMARSHALL: 7068d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 707da6c28aaSamw if (!valp) { 708da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 709da6c28aaSamw return (0); 710da6c28aaSamw } 711da6c28aaSamw if (outer_ref->backptr) 712da6c28aaSamw *outer_ref->backptr = valp; 713da6c28aaSamw outer_ref->datum = valp; 714da6c28aaSamw break; 715da6c28aaSamw 716da6c28aaSamw default: 717da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 718da6c28aaSamw return (0); 719da6c28aaSamw } 720da6c28aaSamw 721da6c28aaSamw bzero(&myref, sizeof (myref)); 7228d7e4166Sjose borrego myref.stream = nds; 723da6c28aaSamw myref.enclosing = outer_ref; 724da6c28aaSamw myref.ti = outer_ref->ti; 725da6c28aaSamw myref.datum = outer_ref->datum; 726da6c28aaSamw myref.name = "FIXED-VALUE"; 727da6c28aaSamw myref.outer_flags = NDR_F_NONE; 728da6c28aaSamw myref.inner_flags = NDR_F_NONE; 729da6c28aaSamw 730da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset; 731da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 732da6c28aaSamw 7338d7e4166Sjose borrego rc = ndr_inner(&myref); 734da6c28aaSamw if (!rc) 735da6c28aaSamw return (rc); /* error already set */ 736da6c28aaSamw 7378d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 738da6c28aaSamw return (1); 739da6c28aaSamw } 740da6c28aaSamw 741da6c28aaSamw int 7428d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref) 743da6c28aaSamw { 7448d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 7458d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 7468d7e4166Sjose borrego ndr_ref_t myref; 747*1ca4e8dfSGordon Ross char *valp = NULL; 748da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 749da6c28aaSamw int is_union = NDR_IS_UNION(ti); 750da6c28aaSamw int is_string = NDR_IS_STRING(ti); 751da6c28aaSamw int rc; 752da6c28aaSamw unsigned n_hdr; 753da6c28aaSamw unsigned n_fixed; 754da6c28aaSamw unsigned n_variable; 755da6c28aaSamw unsigned n_alloc; 756da6c28aaSamw unsigned n_pdu_total; 757da6c28aaSamw int params; 758da6c28aaSamw 759da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 760da6c28aaSamw 761da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 762da6c28aaSamw assert(params == NDR_F_DIMENSION_IS); 763da6c28aaSamw 764da6c28aaSamw /* no header for this */ 765da6c28aaSamw n_hdr = 0; 766da6c28aaSamw 767da6c28aaSamw /* fixed part -- exactly dimension_is of these */ 768da6c28aaSamw n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 769da6c28aaSamw assert(n_fixed > 0); 770da6c28aaSamw 771da6c28aaSamw /* variable part -- exactly none of these */ 772da6c28aaSamw n_variable = 0; 773da6c28aaSamw 774da6c28aaSamw /* sum them up to determine the PDU space required */ 775da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 776da6c28aaSamw 777da6c28aaSamw /* similar sum to determine how much local memory is required */ 778da6c28aaSamw n_alloc = n_fixed + n_variable; 779da6c28aaSamw 7808d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 781da6c28aaSamw if (!rc) 782da6c28aaSamw return (rc); /* error already set */ 783da6c28aaSamw 7848d7e4166Sjose borrego switch (nds->m_op) { 785da6c28aaSamw case NDR_M_OP_MARSHALL: 786da6c28aaSamw valp = outer_ref->datum; 78796a62adaSjoyce mcintosh if (!valp) { 78896a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 78996a62adaSjoyce mcintosh return (0); 79096a62adaSjoyce mcintosh } 791f96bd5c8SAlan Wright if (outer_ref->backptr) 792da6c28aaSamw assert(valp == *outer_ref->backptr); 793da6c28aaSamw break; 794da6c28aaSamw 795da6c28aaSamw case NDR_M_OP_UNMARSHALL: 7968d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 797da6c28aaSamw if (!valp) { 798da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 799da6c28aaSamw return (0); 800da6c28aaSamw } 801da6c28aaSamw if (outer_ref->backptr) 802da6c28aaSamw *outer_ref->backptr = valp; 803da6c28aaSamw outer_ref->datum = valp; 804da6c28aaSamw break; 805da6c28aaSamw 806da6c28aaSamw default: 807da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 808da6c28aaSamw return (0); 809da6c28aaSamw } 810da6c28aaSamw 811da6c28aaSamw bzero(&myref, sizeof (myref)); 8128d7e4166Sjose borrego myref.stream = nds; 813da6c28aaSamw myref.enclosing = outer_ref; 814da6c28aaSamw myref.ti = outer_ref->ti; 815da6c28aaSamw myref.datum = outer_ref->datum; 816da6c28aaSamw myref.name = "FIXED-ARRAY"; 817da6c28aaSamw myref.outer_flags = NDR_F_NONE; 818da6c28aaSamw myref.inner_flags = NDR_F_DIMENSION_IS; 819da6c28aaSamw myref.dimension_is = outer_ref->dimension_is; 820da6c28aaSamw 821da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset; 822da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 823da6c28aaSamw 8248d7e4166Sjose borrego rc = ndr_inner(&myref); 825da6c28aaSamw if (!rc) 826da6c28aaSamw return (rc); /* error already set */ 827da6c28aaSamw 8288d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 829da6c28aaSamw return (1); 830da6c28aaSamw } 831da6c28aaSamw 832da6c28aaSamw int 8338d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref) 834da6c28aaSamw { 8358d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 8368d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 8378d7e4166Sjose borrego ndr_ref_t myref; 838*1ca4e8dfSGordon Ross char *valp = NULL; 839da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 840da6c28aaSamw int is_union = NDR_IS_UNION(ti); 841da6c28aaSamw int is_string = NDR_IS_STRING(ti); 842da6c28aaSamw unsigned long size_is; 843da6c28aaSamw int rc; 844da6c28aaSamw unsigned n_hdr; 845da6c28aaSamw unsigned n_fixed; 846da6c28aaSamw unsigned n_variable; 847da6c28aaSamw unsigned n_alloc; 848da6c28aaSamw unsigned n_pdu_total; 849f96bd5c8SAlan Wright unsigned n_ptr_offset; 850da6c28aaSamw int params; 851da6c28aaSamw 852da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 853da6c28aaSamw 854da6c28aaSamw assert(!is_varlen && !is_string && !is_union); 855f96bd5c8SAlan Wright assert(params & NDR_F_SIZE_IS); 856da6c28aaSamw 857da6c28aaSamw /* conformant header for this */ 858da6c28aaSamw n_hdr = 4; 859da6c28aaSamw 860da6c28aaSamw /* fixed part -- exactly none of these */ 861da6c28aaSamw n_fixed = 0; 862da6c28aaSamw 863da6c28aaSamw /* variable part -- exactly size_of of these */ 864da6c28aaSamw /* notice that it is the **fixed** size of the ti */ 865da6c28aaSamw n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 866da6c28aaSamw 867da6c28aaSamw /* sum them up to determine the PDU space required */ 868da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 869da6c28aaSamw 870da6c28aaSamw /* similar sum to determine how much local memory is required */ 871da6c28aaSamw n_alloc = n_fixed + n_variable; 872da6c28aaSamw 8738d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 874da6c28aaSamw if (!rc) 875da6c28aaSamw return (rc); /* error already set */ 876da6c28aaSamw 8778d7e4166Sjose borrego switch (nds->m_op) { 878da6c28aaSamw case NDR_M_OP_MARSHALL: 879da6c28aaSamw size_is = outer_ref->size_is; 8808d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 881da6c28aaSamw if (!rc) 882da6c28aaSamw return (0); /* error already set */ 883da6c28aaSamw 884da6c28aaSamw valp = outer_ref->datum; 88596a62adaSjoyce mcintosh if (!valp) { 88696a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 88796a62adaSjoyce mcintosh return (0); 88896a62adaSjoyce mcintosh } 889f96bd5c8SAlan Wright if (outer_ref->backptr) 890da6c28aaSamw assert(valp == *outer_ref->backptr); 891f96bd5c8SAlan Wright n_ptr_offset = 4; 892da6c28aaSamw break; 893da6c28aaSamw 894da6c28aaSamw case NDR_M_OP_UNMARSHALL: 895f96bd5c8SAlan Wright if (params & NDR_F_IS_REFERENCE) { 896f96bd5c8SAlan Wright size_is = outer_ref->size_is; 897f96bd5c8SAlan Wright n_ptr_offset = 0; 898f96bd5c8SAlan Wright } else { 899f96bd5c8SAlan Wright /* NDR_F_IS_POINTER */ 900f96bd5c8SAlan Wright rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 901f96bd5c8SAlan Wright if (!rc) 902f96bd5c8SAlan Wright return (0); /* error already set */ 903f96bd5c8SAlan Wright 904f96bd5c8SAlan Wright if (size_is != outer_ref->size_is) { 905f96bd5c8SAlan Wright NDR_SET_ERROR(outer_ref, 906f96bd5c8SAlan Wright NDR_ERR_SIZE_IS_MISMATCH_PDU); 907f96bd5c8SAlan Wright return (0); 908f96bd5c8SAlan Wright } 909da6c28aaSamw 910f96bd5c8SAlan Wright n_ptr_offset = 4; 911da6c28aaSamw } 912da6c28aaSamw 9133ad684d6Sjb if (size_is > 0) { 9148d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 9153ad684d6Sjb if (!valp) { 9163ad684d6Sjb NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 9173ad684d6Sjb return (0); 9183ad684d6Sjb } 919da6c28aaSamw } 9203ad684d6Sjb 921da6c28aaSamw if (outer_ref->backptr) 922da6c28aaSamw *outer_ref->backptr = valp; 923da6c28aaSamw outer_ref->datum = valp; 924da6c28aaSamw break; 925da6c28aaSamw 926da6c28aaSamw default: 927da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 928da6c28aaSamw return (0); 929da6c28aaSamw } 930da6c28aaSamw 931da6c28aaSamw outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 932da6c28aaSamw outer_ref->type_flags = NDR_F_NONE; 933da6c28aaSamw outer_ref->inner_flags = NDR_F_NONE; 934da6c28aaSamw 9353ad684d6Sjb if (size_is > 0) { 9363ad684d6Sjb bzero(&myref, sizeof (myref)); 9378d7e4166Sjose borrego myref.stream = nds; 9383ad684d6Sjb myref.enclosing = outer_ref; 9393ad684d6Sjb myref.ti = outer_ref->ti; 9403ad684d6Sjb myref.datum = outer_ref->datum; 9413ad684d6Sjb myref.name = "CONFORMANT-ARRAY"; 9423ad684d6Sjb myref.outer_flags = NDR_F_NONE; 9433ad684d6Sjb myref.inner_flags = NDR_F_SIZE_IS; 9443ad684d6Sjb myref.size_is = outer_ref->size_is; 9453ad684d6Sjb 9463ad684d6Sjb myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 9473ad684d6Sjb myref.dimension_is = outer_ref->size_is; /* convenient */ 9483ad684d6Sjb 949f96bd5c8SAlan Wright myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset; 9503ad684d6Sjb 9518d7e4166Sjose borrego rc = ndr_inner(&myref); 9523ad684d6Sjb if (!rc) 9533ad684d6Sjb return (rc); /* error already set */ 9543ad684d6Sjb } 955da6c28aaSamw 9568d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 957da6c28aaSamw return (1); 958da6c28aaSamw } 959da6c28aaSamw 960da6c28aaSamw int 9618d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref) 962da6c28aaSamw { 9638d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 9648d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 9658d7e4166Sjose borrego ndr_ref_t myref; 966*1ca4e8dfSGordon Ross char *valp = NULL; 967da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 968da6c28aaSamw int is_union = NDR_IS_UNION(ti); 969da6c28aaSamw int is_string = NDR_IS_STRING(ti); 970da6c28aaSamw unsigned long size_is; 971da6c28aaSamw int rc; 972da6c28aaSamw unsigned n_hdr; 973da6c28aaSamw unsigned n_fixed; 974da6c28aaSamw unsigned n_variable; 975da6c28aaSamw unsigned n_alloc; 976da6c28aaSamw unsigned n_pdu_total; 977da6c28aaSamw int params; 978da6c28aaSamw 979da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 980da6c28aaSamw 981da6c28aaSamw assert(is_varlen && !is_string && !is_union); 982da6c28aaSamw assert(params == NDR_F_NONE); 983da6c28aaSamw 984da6c28aaSamw /* conformant header for this */ 985da6c28aaSamw n_hdr = 4; 986da6c28aaSamw 987da6c28aaSamw /* fixed part -- exactly one of these */ 988da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 989da6c28aaSamw 990da6c28aaSamw /* variable part -- exactly size_of of these */ 991da6c28aaSamw n_variable = 0; /* 0 for the moment */ 992da6c28aaSamw 993da6c28aaSamw /* sum them up to determine the PDU space required */ 994da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 995da6c28aaSamw 996da6c28aaSamw /* similar sum to determine how much local memory is required */ 997da6c28aaSamw n_alloc = n_fixed + n_variable; 998da6c28aaSamw 999da6c28aaSamw /* For the moment, grow enough for the fixed-size part */ 10008d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1001da6c28aaSamw if (!rc) 1002da6c28aaSamw return (rc); /* error already set */ 1003da6c28aaSamw 10048d7e4166Sjose borrego switch (nds->m_op) { 1005da6c28aaSamw case NDR_M_OP_MARSHALL: 1006da6c28aaSamw /* 1007da6c28aaSamw * We don't know the size yet. We have to wait for 1008da6c28aaSamw * it. Proceed with the fixed-size part, and await 10098d7e4166Sjose borrego * the call to ndr_size_is(). 1010da6c28aaSamw */ 1011da6c28aaSamw size_is = 0; 10128d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1013da6c28aaSamw if (!rc) 1014da6c28aaSamw return (0); /* error already set */ 1015da6c28aaSamw 1016da6c28aaSamw valp = outer_ref->datum; 101796a62adaSjoyce mcintosh if (!valp) { 101896a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 101996a62adaSjoyce mcintosh return (0); 102096a62adaSjoyce mcintosh } 1021f96bd5c8SAlan Wright if (outer_ref->backptr) 1022da6c28aaSamw assert(valp == *outer_ref->backptr); 1023da6c28aaSamw break; 1024da6c28aaSamw 1025da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1026da6c28aaSamw /* 1027da6c28aaSamw * We know the size of the variable part because 1028da6c28aaSamw * of the CONFORMANT header. We will verify 1029da6c28aaSamw * the header against the [size_is(X)] advice 10308d7e4166Sjose borrego * later when ndr_size_is() is called. 1031da6c28aaSamw */ 10328d7e4166Sjose borrego rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 1033da6c28aaSamw if (!rc) 1034da6c28aaSamw return (0); /* error already set */ 1035da6c28aaSamw 1036da6c28aaSamw /* recalculate metrics */ 1037da6c28aaSamw n_variable = size_is * ti->pdu_size_variable_part; 1038da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1039da6c28aaSamw n_alloc = n_fixed + n_variable; 1040da6c28aaSamw 10418d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1042da6c28aaSamw if (!rc) 1043da6c28aaSamw return (rc); /* error already set */ 1044da6c28aaSamw 1045da6c28aaSamw outer_ref->size_is = size_is; /* verified later */ 1046da6c28aaSamw 10478d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1048da6c28aaSamw if (!valp) { 1049da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1050da6c28aaSamw return (0); 1051da6c28aaSamw } 1052da6c28aaSamw if (outer_ref->backptr) 1053da6c28aaSamw *outer_ref->backptr = valp; 1054da6c28aaSamw outer_ref->datum = valp; 1055da6c28aaSamw break; 1056da6c28aaSamw 1057da6c28aaSamw default: 1058da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1059da6c28aaSamw return (0); 1060da6c28aaSamw } 1061da6c28aaSamw 10623ad684d6Sjb outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 10633ad684d6Sjb outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 10643ad684d6Sjb outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 10653ad684d6Sjb 1066da6c28aaSamw bzero(&myref, sizeof (myref)); 10678d7e4166Sjose borrego myref.stream = nds; 1068da6c28aaSamw myref.enclosing = outer_ref; 1069da6c28aaSamw myref.ti = outer_ref->ti; 1070da6c28aaSamw myref.datum = outer_ref->datum; 1071da6c28aaSamw myref.name = "CONFORMANT-CONSTRUCT"; 1072da6c28aaSamw myref.outer_flags = NDR_F_NONE; 1073da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1074da6c28aaSamw myref.size_is = outer_ref->size_is; 1075da6c28aaSamw 1076da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset + 4; 1077da6c28aaSamw 10788d7e4166Sjose borrego rc = ndr_inner(&myref); 1079da6c28aaSamw if (!rc) 1080da6c28aaSamw return (rc); /* error already set */ 1081da6c28aaSamw 10828d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1083da6c28aaSamw 1084da6c28aaSamw if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 1085da6c28aaSamw NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 1086da6c28aaSamw return (0); 1087da6c28aaSamw } 1088da6c28aaSamw 1089da6c28aaSamw return (1); 1090da6c28aaSamw } 1091da6c28aaSamw 1092da6c28aaSamw int 10938d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref) 1094da6c28aaSamw { 1095*1ca4e8dfSGordon Ross ndr_stream_t *nds = ref->stream; 1096*1ca4e8dfSGordon Ross ndr_ref_t *outer_ref = nds->outer_current; 10978d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 1098da6c28aaSamw unsigned long size_is; 1099da6c28aaSamw int rc; 1100da6c28aaSamw unsigned n_hdr; 1101da6c28aaSamw unsigned n_fixed; 1102da6c28aaSamw unsigned n_variable; 1103da6c28aaSamw unsigned n_pdu_total; 1104da6c28aaSamw 1105da6c28aaSamw assert(ref->inner_flags & NDR_F_SIZE_IS); 1106da6c28aaSamw size_is = ref->size_is; 1107da6c28aaSamw 1108da6c28aaSamw if (outer_ref->type_flags != NDR_F_SIZE_IS) { 1109da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 1110da6c28aaSamw return (0); 1111da6c28aaSamw } 1112da6c28aaSamw 1113da6c28aaSamw if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 1114da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 1115da6c28aaSamw return (0); 1116da6c28aaSamw } 1117da6c28aaSamw 11188d7e4166Sjose borrego /* repeat metrics, see ndr_conformant_construct() above */ 1119da6c28aaSamw n_hdr = 4; 1120da6c28aaSamw n_fixed = ti->pdu_size_fixed_part; 1121da6c28aaSamw n_variable = size_is * ti->pdu_size_variable_part; 1122da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1123da6c28aaSamw 11248d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1125da6c28aaSamw if (!rc) 1126da6c28aaSamw return (rc); /* error already set */ 1127da6c28aaSamw 11288d7e4166Sjose borrego switch (nds->m_op) { 1129da6c28aaSamw case NDR_M_OP_MARSHALL: 1130da6c28aaSamw /* 1131da6c28aaSamw * We have to set the sizing header and extend 1132da6c28aaSamw * the size of the PDU (already done). 1133da6c28aaSamw */ 11348d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1135da6c28aaSamw if (!rc) 1136da6c28aaSamw return (0); /* error already set */ 1137da6c28aaSamw break; 1138da6c28aaSamw 1139da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1140da6c28aaSamw /* 11418d7e4166Sjose borrego * Allocation done during ndr_conformant_construct(). 1142da6c28aaSamw * All we are doing here is verifying that the 1143da6c28aaSamw * intended size (ref->size_is) matches the sizing header. 1144da6c28aaSamw */ 1145da6c28aaSamw if (size_is != outer_ref->size_is) { 1146da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 1147da6c28aaSamw return (0); 1148da6c28aaSamw } 1149da6c28aaSamw break; 1150da6c28aaSamw 1151da6c28aaSamw default: 1152da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1153da6c28aaSamw return (0); 1154da6c28aaSamw } 1155da6c28aaSamw 1156da6c28aaSamw outer_ref->inner_flags |= NDR_F_SIZE_IS; 1157da6c28aaSamw outer_ref->size_is = ref->size_is; 1158da6c28aaSamw return (1); 1159da6c28aaSamw } 1160da6c28aaSamw 1161da6c28aaSamw int 11628d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref) 1163da6c28aaSamw { 11648d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 1165*1ca4e8dfSGordon Ross ndr_typeinfo_t *ti = outer_ref->ti; 11668d7e4166Sjose borrego ndr_ref_t myref; 1167*1ca4e8dfSGordon Ross char *valp = NULL; 1168da6c28aaSamw unsigned is_varlen = ti->pdu_size_variable_part; 1169da6c28aaSamw int is_union = NDR_IS_UNION(ti); 1170da6c28aaSamw int is_string = NDR_IS_STRING(ti); 1171da6c28aaSamw int rc; 1172da6c28aaSamw unsigned n_zeroes; 1173da6c28aaSamw unsigned ix; 1174da6c28aaSamw unsigned long size_is; 1175da6c28aaSamw unsigned long first_is; 1176da6c28aaSamw unsigned long length_is; 1177da6c28aaSamw unsigned n_hdr; 1178da6c28aaSamw unsigned n_fixed; 1179da6c28aaSamw unsigned n_variable; 1180da6c28aaSamw unsigned n_alloc; 1181da6c28aaSamw unsigned n_pdu_total; 1182da6c28aaSamw int params; 1183da6c28aaSamw 1184da6c28aaSamw params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 1185da6c28aaSamw 1186da6c28aaSamw assert(is_varlen && is_string && !is_union); 1187da6c28aaSamw assert(params == NDR_F_NONE); 1188da6c28aaSamw 1189da6c28aaSamw /* string header for this: size_is first_is length_is */ 1190da6c28aaSamw n_hdr = 12; 1191da6c28aaSamw 1192da6c28aaSamw /* fixed part -- exactly none of these */ 1193da6c28aaSamw n_fixed = 0; 1194da6c28aaSamw 11958d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_hdr)) 1196da6c28aaSamw return (0); /* error already set */ 1197da6c28aaSamw 11988d7e4166Sjose borrego switch (nds->m_op) { 1199da6c28aaSamw case NDR_M_OP_MARSHALL: 1200da6c28aaSamw valp = outer_ref->datum; 120196a62adaSjoyce mcintosh if (!valp) { 120296a62adaSjoyce mcintosh NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD); 120396a62adaSjoyce mcintosh return (0); 120496a62adaSjoyce mcintosh } 1205da6c28aaSamw 1206da6c28aaSamw if (outer_ref->backptr) 1207da6c28aaSamw assert(valp == *outer_ref->backptr); 1208da6c28aaSamw 1209da6c28aaSamw if (ti == &ndt_s_wchar) { 1210da6c28aaSamw /* 1211a0aa776eSAlan Wright * size_is is the number of characters in the 1212a0aa776eSAlan Wright * (multibyte) string, including the null. 12133299f39fSGordon Ross * In other words, symbols, not bytes. 1214da6c28aaSamw */ 12153299f39fSGordon Ross size_t wlen; 12163299f39fSGordon Ross wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX); 12173299f39fSGordon Ross if (wlen == (size_t)-1) { 12183299f39fSGordon Ross /* illegal sequence error? */ 1219da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1220da6c28aaSamw return (0); 1221da6c28aaSamw } 12223299f39fSGordon Ross if ((nds->flags & NDS_F_NONULL) == 0) 12233299f39fSGordon Ross wlen++; 12243299f39fSGordon Ross if (wlen > NDR_STRING_MAX) { 12253299f39fSGordon Ross NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 12263299f39fSGordon Ross return (0); 12273299f39fSGordon Ross } 12283299f39fSGordon Ross size_is = wlen; 1229da6c28aaSamw } else { 1230da6c28aaSamw valp = outer_ref->datum; 1231da6c28aaSamw n_zeroes = 0; 1232f96bd5c8SAlan Wright for (ix = 0; ix < NDR_STRING_MAX; ix++) { 1233da6c28aaSamw if (valp[ix] == 0) { 1234da6c28aaSamw n_zeroes++; 1235da6c28aaSamw if (n_zeroes >= is_varlen && 1236da6c28aaSamw ix % is_varlen == 0) { 1237da6c28aaSamw break; 1238da6c28aaSamw } 1239da6c28aaSamw } else { 1240da6c28aaSamw n_zeroes = 0; 1241da6c28aaSamw } 1242da6c28aaSamw } 1243f96bd5c8SAlan Wright if (ix >= NDR_STRING_MAX) { 1244da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1245da6c28aaSamw return (0); 1246da6c28aaSamw } 1247da6c28aaSamw size_is = ix+1; 1248da6c28aaSamw } 1249da6c28aaSamw 1250da6c28aaSamw first_is = 0; 125155bf511dSas 12528d7e4166Sjose borrego if (nds->flags & NDS_F_NOTERM) 125355bf511dSas length_is = size_is - 1; 125455bf511dSas else 125555bf511dSas length_is = size_is; 1256da6c28aaSamw 12578d7e4166Sjose borrego if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) || 12588d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 4, &first_is) || 12598d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 8, &length_is)) 1260da6c28aaSamw return (0); /* error already set */ 1261da6c28aaSamw break; 1262da6c28aaSamw 1263da6c28aaSamw case NDR_M_OP_UNMARSHALL: 12648d7e4166Sjose borrego if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) || 12658d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 4, &first_is) || 12668d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 8, &length_is)) 1267da6c28aaSamw return (0); /* error already set */ 1268da6c28aaSamw 1269da6c28aaSamw /* 1270*1ca4e8dfSGordon Ross * Enforce bounds on: size_is, first_is, length_is 1271*1ca4e8dfSGordon Ross * 1272da6c28aaSamw * In addition to the first_is check, we used to check that 1273da6c28aaSamw * size_is or size_is-1 was equal to length_is but Windows95 1274da6c28aaSamw * doesn't conform to this "rule" (see variable part below). 1275da6c28aaSamw * The srvmgr tool for Windows95 sent the following values 1276da6c28aaSamw * for a path string: 1277da6c28aaSamw * 1278da6c28aaSamw * size_is = 261 (0x105) 1279da6c28aaSamw * first_is = 0 1280da6c28aaSamw * length_is = 53 (0x35) 1281da6c28aaSamw * 1282da6c28aaSamw * The length_is was correct (for the given path) but the 1283da6c28aaSamw * size_is was the maximum path length rather than being 1284da6c28aaSamw * related to length_is. 1285da6c28aaSamw */ 1286*1ca4e8dfSGordon Ross if (size_is > NDR_STRING_MAX) { 1287*1ca4e8dfSGordon Ross NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1288*1ca4e8dfSGordon Ross return (0); 1289*1ca4e8dfSGordon Ross } 1290da6c28aaSamw if (first_is != 0) { 1291da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1292da6c28aaSamw return (0); 1293da6c28aaSamw } 1294*1ca4e8dfSGordon Ross if (length_is > size_is) { 1295*1ca4e8dfSGordon Ross NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1296*1ca4e8dfSGordon Ross return (0); 1297*1ca4e8dfSGordon Ross } 1298da6c28aaSamw 1299da6c28aaSamw if (ti == &ndt_s_wchar) { 1300da6c28aaSamw /* 1301da6c28aaSamw * Decoding Unicode to UTF-8; we need to allow 1302da6c28aaSamw * for the maximum possible char size. It would 1303da6c28aaSamw * be nice to use mbequiv_strlen but the string 1304da6c28aaSamw * may not be null terminated. 1305da6c28aaSamw */ 13063299f39fSGordon Ross n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX; 1307da6c28aaSamw } else { 1308da6c28aaSamw n_alloc = (size_is + 1) * is_varlen; 1309da6c28aaSamw } 1310da6c28aaSamw 13118d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1312da6c28aaSamw if (!valp) { 1313da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1314da6c28aaSamw return (0); 1315da6c28aaSamw } 1316da6c28aaSamw 1317da6c28aaSamw bzero(valp, (size_is+1) * is_varlen); 1318da6c28aaSamw 1319da6c28aaSamw if (outer_ref->backptr) 1320da6c28aaSamw *outer_ref->backptr = valp; 1321da6c28aaSamw outer_ref->datum = valp; 1322da6c28aaSamw break; 1323da6c28aaSamw 1324da6c28aaSamw default: 1325da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1326da6c28aaSamw return (0); 1327da6c28aaSamw } 1328da6c28aaSamw 1329da6c28aaSamw /* 1330da6c28aaSamw * Variable part - exactly length_is of these. 1331da6c28aaSamw * 1332da6c28aaSamw * Usually, length_is is same as size_is and includes nul. 1333da6c28aaSamw * Some protocols use length_is = size_is-1, and length_is does 1334da6c28aaSamw * not include the nul (which is more consistent with DCE spec). 1335da6c28aaSamw * If the length_is is 0, there is no data following the 1336da6c28aaSamw * sizing header, regardless of size_is. 1337da6c28aaSamw */ 1338da6c28aaSamw n_variable = length_is * is_varlen; 1339da6c28aaSamw 1340da6c28aaSamw /* sum them up to determine the PDU space required */ 1341da6c28aaSamw n_pdu_total = n_hdr + n_fixed + n_variable; 1342da6c28aaSamw 1343da6c28aaSamw /* similar sum to determine how much local memory is required */ 1344da6c28aaSamw n_alloc = n_fixed + n_variable; 1345da6c28aaSamw 13468d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1347da6c28aaSamw if (!rc) 1348da6c28aaSamw return (rc); /* error already set */ 1349da6c28aaSamw 1350da6c28aaSamw if (length_is > 0) { 1351da6c28aaSamw bzero(&myref, sizeof (myref)); 13528d7e4166Sjose borrego myref.stream = nds; 1353da6c28aaSamw myref.enclosing = outer_ref; 1354da6c28aaSamw myref.ti = outer_ref->ti; 1355da6c28aaSamw myref.datum = outer_ref->datum; 1356da6c28aaSamw myref.name = "OUTER-STRING"; 1357da6c28aaSamw myref.outer_flags = NDR_F_IS_STRING; 1358da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1359da6c28aaSamw 1360da6c28aaSamw /* 13618d7e4166Sjose borrego * Set up size_is and strlen_is for ndr_s_wchar. 1362da6c28aaSamw */ 1363dc20a302Sas myref.size_is = size_is; 1364da6c28aaSamw myref.strlen_is = length_is; 1365da6c28aaSamw } 1366da6c28aaSamw 1367da6c28aaSamw myref.pdu_offset = outer_ref->pdu_offset + 12; 1368da6c28aaSamw 1369da6c28aaSamw /* 1370da6c28aaSamw * Don't try to decode empty strings. 1371da6c28aaSamw */ 1372da6c28aaSamw if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 13738d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1374da6c28aaSamw return (1); 1375da6c28aaSamw } 1376da6c28aaSamw 1377da6c28aaSamw if ((size_is != 0) && (length_is != 0)) { 13788d7e4166Sjose borrego rc = ndr_inner(&myref); 1379da6c28aaSamw if (!rc) 1380da6c28aaSamw return (rc); /* error already set */ 1381da6c28aaSamw } 1382da6c28aaSamw 13838d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1384da6c28aaSamw return (1); 1385da6c28aaSamw } 1386da6c28aaSamw 1387da6c28aaSamw int 13888d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset, 1389da6c28aaSamw unsigned long *sizing_p) 1390da6c28aaSamw { 1391*1ca4e8dfSGordon Ross ndr_stream_t *nds = outer_ref->stream; 13928d7e4166Sjose borrego unsigned long pdu_offset; 13938d7e4166Sjose borrego int rc; 1394da6c28aaSamw 1395da6c28aaSamw pdu_offset = outer_ref->pdu_offset + offset; 1396da6c28aaSamw 13978d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 13988d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 13998d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1400da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1401da6c28aaSamw return (0); 1402da6c28aaSamw } 1403da6c28aaSamw 14048d7e4166Sjose borrego switch (nds->m_op) { 1405da6c28aaSamw case NDR_M_OP_MARSHALL: 1406da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1407da6c28aaSamw return (0); 1408da6c28aaSamw 1409da6c28aaSamw case NDR_M_OP_UNMARSHALL: 14108d7e4166Sjose borrego rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14118d7e4166Sjose borrego nds->swap, outer_ref); 1412da6c28aaSamw break; 1413da6c28aaSamw 1414da6c28aaSamw default: 1415da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1416da6c28aaSamw return (0); 1417da6c28aaSamw } 1418da6c28aaSamw 1419da6c28aaSamw return (rc); 1420da6c28aaSamw } 1421da6c28aaSamw 1422da6c28aaSamw int 14238d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset, 1424da6c28aaSamw unsigned long *sizing_p) 1425da6c28aaSamw { 1426*1ca4e8dfSGordon Ross ndr_stream_t *nds = outer_ref->stream; 14278d7e4166Sjose borrego unsigned long pdu_offset; 14288d7e4166Sjose borrego int rc; 1429da6c28aaSamw 1430da6c28aaSamw pdu_offset = outer_ref->pdu_offset + offset; 1431da6c28aaSamw 14328d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 14338d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 14348d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1435da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1436da6c28aaSamw return (0); 1437da6c28aaSamw } 1438da6c28aaSamw 14398d7e4166Sjose borrego switch (nds->m_op) { 1440da6c28aaSamw case NDR_M_OP_MARSHALL: 14418d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14428d7e4166Sjose borrego nds->swap, outer_ref); 1443da6c28aaSamw break; 1444da6c28aaSamw 1445da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1446da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1447da6c28aaSamw return (0); 1448da6c28aaSamw 1449da6c28aaSamw default: 1450da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1451da6c28aaSamw return (0); 1452da6c28aaSamw } 1453da6c28aaSamw 1454da6c28aaSamw return (rc); 1455da6c28aaSamw } 1456da6c28aaSamw 1457da6c28aaSamw /* 1458da6c28aaSamw * All OUTER constructs begin on a mod4 (dword) boundary - except 1459da6c28aaSamw * for the ones that don't: some MSRPC calls appear to use word or 1460da6c28aaSamw * packed alignment. Strings appear to be dword aligned. 1461da6c28aaSamw */ 1462da6c28aaSamw int 14638d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref) 1464da6c28aaSamw { 1465*1ca4e8dfSGordon Ross ndr_stream_t *nds = outer_ref->stream; 14668d7e4166Sjose borrego int rc; 14678d7e4166Sjose borrego unsigned n_pad; 14688d7e4166Sjose borrego unsigned align; 1469da6c28aaSamw 1470da6c28aaSamw if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 1471da6c28aaSamw align = outer_ref->ti->alignment; 14728d7e4166Sjose borrego n_pad = ((align + 1) - nds->pdu_scan_offset) & align; 1473da6c28aaSamw } else { 14748d7e4166Sjose borrego n_pad = NDR_ALIGN4(nds->pdu_scan_offset); 1475da6c28aaSamw } 1476da6c28aaSamw 1477da6c28aaSamw if (n_pad == 0) 1478da6c28aaSamw return (1); /* already aligned, often the case */ 1479da6c28aaSamw 14808d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_pad)) 1481da6c28aaSamw return (0); /* error already set */ 1482da6c28aaSamw 14838d7e4166Sjose borrego switch (nds->m_op) { 1484da6c28aaSamw case NDR_M_OP_MARSHALL: 14858d7e4166Sjose borrego rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref); 1486da6c28aaSamw if (!rc) { 1487da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 1488da6c28aaSamw return (0); 1489da6c28aaSamw } 1490da6c28aaSamw break; 1491da6c28aaSamw 1492da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1493da6c28aaSamw break; 1494da6c28aaSamw 1495da6c28aaSamw default: 1496da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1497da6c28aaSamw return (0); 1498da6c28aaSamw } 1499da6c28aaSamw 15008d7e4166Sjose borrego nds->pdu_scan_offset += n_pad; 1501da6c28aaSamw return (1); 1502da6c28aaSamw } 1503da6c28aaSamw 1504da6c28aaSamw int 15058d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total) 1506da6c28aaSamw { 1507*1ca4e8dfSGordon Ross ndr_stream_t *nds = outer_ref->stream; 15088d7e4166Sjose borrego unsigned long pdu_want_size; 15098d7e4166Sjose borrego int rc, is_ok = 0; 1510da6c28aaSamw 15118d7e4166Sjose borrego pdu_want_size = nds->pdu_scan_offset + n_total; 1512da6c28aaSamw 15138d7e4166Sjose borrego if (pdu_want_size <= nds->pdu_max_size) { 1514da6c28aaSamw is_ok = 1; 1515da6c28aaSamw } 1516da6c28aaSamw 15178d7e4166Sjose borrego switch (nds->m_op) { 1518da6c28aaSamw case NDR_M_OP_MARSHALL: 1519da6c28aaSamw if (is_ok) 1520da6c28aaSamw break; 15218d7e4166Sjose borrego rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref); 1522da6c28aaSamw if (!rc) { 1523da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 1524da6c28aaSamw return (0); 1525da6c28aaSamw } 1526da6c28aaSamw break; 1527da6c28aaSamw 1528da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1529da6c28aaSamw if (is_ok) 1530da6c28aaSamw break; 1531da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 1532da6c28aaSamw return (0); 1533da6c28aaSamw 1534da6c28aaSamw default: 1535da6c28aaSamw NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1536da6c28aaSamw return (0); 1537da6c28aaSamw } 1538da6c28aaSamw 15398d7e4166Sjose borrego if (nds->pdu_size < pdu_want_size) 15408d7e4166Sjose borrego nds->pdu_size = pdu_want_size; 1541da6c28aaSamw 1542da6c28aaSamw outer_ref->pdu_end_offset = pdu_want_size; 1543da6c28aaSamw return (1); 1544da6c28aaSamw } 1545da6c28aaSamw 1546da6c28aaSamw /* 1547da6c28aaSamw * INNER ELEMENTS 1548da6c28aaSamw * 1549da6c28aaSamw * The local datum (arg_ref->datum) already exists, there is no need to 1550da6c28aaSamw * malloc() it. The datum should point at a member of a structure. 1551da6c28aaSamw * 15528d7e4166Sjose borrego * For the most part, ndr_inner() and its helpers are just a sanity 1553da6c28aaSamw * check. The underlying ti->ndr_func() could be called immediately 1554da6c28aaSamw * for non-pointer elements. For the sake of robustness, we detect 1555da6c28aaSamw * run-time errors here. Most of the situations this protects against 1556da6c28aaSamw * have already been checked by the IDL compiler. This is also a 1557da6c28aaSamw * common point for processing of all data, and so is a convenient 1558da6c28aaSamw * place to work from for debugging. 1559da6c28aaSamw */ 1560da6c28aaSamw int 15618d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref) 1562da6c28aaSamw { 1563*1ca4e8dfSGordon Ross ndr_typeinfo_t *ti = arg_ref->ti; 1564da6c28aaSamw int is_varlen = ti->pdu_size_variable_part; 1565da6c28aaSamw int is_union = NDR_IS_UNION(ti); 1566da6c28aaSamw int error = NDR_ERR_INNER_PARAMS_BAD; 1567da6c28aaSamw int params; 1568da6c28aaSamw 1569da6c28aaSamw params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1570da6c28aaSamw 1571da6c28aaSamw switch (params) { 1572da6c28aaSamw case NDR_F_NONE: 1573da6c28aaSamw if (is_union) { 1574da6c28aaSamw error = NDR_ERR_SWITCH_VALUE_MISSING; 1575da6c28aaSamw break; 1576da6c28aaSamw } 1577da6c28aaSamw return (*ti->ndr_func)(arg_ref); 1578da6c28aaSamw 1579da6c28aaSamw case NDR_F_SIZE_IS: 1580da6c28aaSamw case NDR_F_DIMENSION_IS: 1581da6c28aaSamw case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 1582da6c28aaSamw case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 1583da6c28aaSamw if (is_varlen) { 1584da6c28aaSamw error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 1585da6c28aaSamw break; 1586da6c28aaSamw } 1587da6c28aaSamw if (is_union) { 1588da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1589da6c28aaSamw break; 1590da6c28aaSamw } 1591da6c28aaSamw if (params & NDR_F_IS_POINTER) 15928d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1593da6c28aaSamw else if (params & NDR_F_IS_REFERENCE) 15948d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1595da6c28aaSamw else 15968d7e4166Sjose borrego return (ndr_inner_array(arg_ref)); 1597da6c28aaSamw 1598da6c28aaSamw case NDR_F_IS_POINTER: /* type is pointer to one something */ 1599da6c28aaSamw if (is_union) { 1600da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1601da6c28aaSamw break; 1602da6c28aaSamw } 16038d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1604da6c28aaSamw 1605da6c28aaSamw case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 1606da6c28aaSamw if (is_union) { 1607da6c28aaSamw error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1608da6c28aaSamw break; 1609da6c28aaSamw } 16108d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1611da6c28aaSamw 1612da6c28aaSamw case NDR_F_SWITCH_IS: 1613da6c28aaSamw if (!is_union) { 1614da6c28aaSamw error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 1615da6c28aaSamw break; 1616da6c28aaSamw } 1617da6c28aaSamw return (*ti->ndr_func)(arg_ref); 1618da6c28aaSamw 1619da6c28aaSamw default: 1620da6c28aaSamw error = NDR_ERR_INNER_PARAMS_BAD; 1621da6c28aaSamw break; 1622da6c28aaSamw } 1623da6c28aaSamw 1624da6c28aaSamw /* 1625da6c28aaSamw * If we get here, something is wrong. Most likely, 1626da6c28aaSamw * the params flags do not match 1627da6c28aaSamw */ 1628da6c28aaSamw NDR_SET_ERROR(arg_ref, error); 1629da6c28aaSamw return (0); 1630da6c28aaSamw } 1631da6c28aaSamw 1632da6c28aaSamw int 16338d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref) 1634da6c28aaSamw { 16358d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1636da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1637*1ca4e8dfSGordon Ross char **valpp = (char **)arg_ref->datum; 1638*1ca4e8dfSGordon Ross ndr_ref_t *outer_ref; 1639da6c28aaSamw 16408d7e4166Sjose borrego if (!ndr__ulong(arg_ref)) 1641da6c28aaSamw return (0); /* error */ 1642da6c28aaSamw if (!*valpp) 1643da6c28aaSamw return (1); /* NULL pointer */ 1644da6c28aaSamw 16458d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1646da6c28aaSamw if (!outer_ref) 1647da6c28aaSamw return (0); /* error already set */ 1648da6c28aaSamw 1649f96bd5c8SAlan Wright /* 1650f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1651f96bd5c8SAlan Wright * Retain pointer flag for conformant arrays. 1652f96bd5c8SAlan Wright */ 1653da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1654f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1655f96bd5c8SAlan Wright outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 1656f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET 1657da6c28aaSamw outer_ref->outer_flags |= NDR_F_BACKPTR; 1658da6c28aaSamw if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1659da6c28aaSamw outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1660da6c28aaSamw } 1661f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */ 1662da6c28aaSamw 1663da6c28aaSamw outer_ref->backptr = valpp; 1664da6c28aaSamw 16658d7e4166Sjose borrego switch (nds->m_op) { 1666da6c28aaSamw case NDR_M_OP_MARSHALL: 1667da6c28aaSamw outer_ref->datum = *valpp; 1668da6c28aaSamw break; 1669da6c28aaSamw 1670da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1671da6c28aaSamw /* 1672da6c28aaSamw * This is probably wrong if the application allocated 1673da6c28aaSamw * memory in advance. Indicate no value for now. 1674da6c28aaSamw * ONC RPC handles this case. 1675da6c28aaSamw */ 1676da6c28aaSamw *valpp = 0; 1677da6c28aaSamw outer_ref->datum = 0; 1678da6c28aaSamw break; 1679da6c28aaSamw } 1680da6c28aaSamw 1681da6c28aaSamw return (1); /* pointer dereference scheduled */ 1682da6c28aaSamw } 1683da6c28aaSamw 1684da6c28aaSamw int 16858d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref) 1686da6c28aaSamw { 16878d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1688da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 16898d7e4166Sjose borrego char **valpp = (char **)arg_ref->datum; 16908d7e4166Sjose borrego ndr_ref_t *outer_ref; 1691da6c28aaSamw 16928d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1693da6c28aaSamw if (!outer_ref) 1694da6c28aaSamw return (0); /* error already set */ 1695da6c28aaSamw 1696f96bd5c8SAlan Wright /* 1697f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1698f96bd5c8SAlan Wright * Retain reference flag for conformant arrays. 1699f96bd5c8SAlan Wright */ 1700da6c28aaSamw outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1701f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1702f96bd5c8SAlan Wright outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 1703da6c28aaSamw #ifdef NDR_INNER_REF_NOT_YET 1704da6c28aaSamw outer_ref->outer_flags |= NDR_F_BACKPTR; 1705da6c28aaSamw if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1706da6c28aaSamw outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1707da6c28aaSamw } 1708da6c28aaSamw #endif /* NDR_INNER_REF_NOT_YET */ 1709da6c28aaSamw 1710da6c28aaSamw outer_ref->backptr = valpp; 1711da6c28aaSamw 17128d7e4166Sjose borrego switch (nds->m_op) { 1713da6c28aaSamw case NDR_M_OP_MARSHALL: 1714da6c28aaSamw outer_ref->datum = *valpp; 1715da6c28aaSamw break; 1716da6c28aaSamw 1717da6c28aaSamw case NDR_M_OP_UNMARSHALL: 1718da6c28aaSamw /* 1719da6c28aaSamw * This is probably wrong if the application allocated 1720da6c28aaSamw * memory in advance. Indicate no value for now. 1721da6c28aaSamw * ONC RPC handles this case. 1722da6c28aaSamw */ 1723da6c28aaSamw *valpp = 0; 1724da6c28aaSamw outer_ref->datum = 0; 1725da6c28aaSamw break; 1726da6c28aaSamw } 1727da6c28aaSamw 1728da6c28aaSamw return (1); /* pointer dereference scheduled */ 1729da6c28aaSamw } 1730da6c28aaSamw 1731da6c28aaSamw int 17328d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref) 1733da6c28aaSamw { 17348d7e4166Sjose borrego ndr_typeinfo_t *ti = encl_ref->ti; 17358d7e4166Sjose borrego ndr_ref_t myref; 1736da6c28aaSamw unsigned long pdu_offset = encl_ref->pdu_offset; 1737da6c28aaSamw unsigned long n_elem; 1738da6c28aaSamw unsigned long i; 1739da6c28aaSamw char name[30]; 1740da6c28aaSamw 1741da6c28aaSamw if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 1742da6c28aaSamw /* now is the time to check/set size */ 17438d7e4166Sjose borrego if (!ndr_size_is(encl_ref)) 1744da6c28aaSamw return (0); /* error already set */ 1745da6c28aaSamw n_elem = encl_ref->size_is; 1746da6c28aaSamw } else { 1747da6c28aaSamw assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 1748da6c28aaSamw n_elem = encl_ref->dimension_is; 1749da6c28aaSamw } 1750da6c28aaSamw 1751da6c28aaSamw bzero(&myref, sizeof (myref)); 1752da6c28aaSamw myref.enclosing = encl_ref; 1753da6c28aaSamw myref.stream = encl_ref->stream; 1754da6c28aaSamw myref.packed_alignment = 0; 1755da6c28aaSamw myref.ti = ti; 1756da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1757da6c28aaSamw 1758da6c28aaSamw for (i = 0; i < n_elem; i++) { 17593299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 1760da6c28aaSamw myref.name = name; 1761da6c28aaSamw myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 1762da6c28aaSamw myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 1763da6c28aaSamw 17648d7e4166Sjose borrego if (!ndr_inner(&myref)) 1765da6c28aaSamw return (0); 1766da6c28aaSamw } 1767da6c28aaSamw 1768da6c28aaSamw return (1); 1769da6c28aaSamw } 1770da6c28aaSamw 1771da6c28aaSamw 1772da6c28aaSamw /* 1773da6c28aaSamw * BASIC TYPES 1774da6c28aaSamw */ 1775da6c28aaSamw #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17768d7e4166Sjose borrego extern int ndr_##TYPE(struct ndr_reference *encl_ref); \ 17778d7e4166Sjose borrego ndr_typeinfo_t ndt_##TYPE = { \ 1778da6c28aaSamw 1, /* NDR version */ \ 1779da6c28aaSamw (SIZE)-1, /* alignment */ \ 1780da6c28aaSamw NDR_F_NONE, /* flags */ \ 17818d7e4166Sjose borrego ndr_##TYPE, /* ndr_func */ \ 1782da6c28aaSamw SIZE, /* pdu_size_fixed_part */ \ 1783da6c28aaSamw 0, /* pdu_size_variable_part */ \ 1784da6c28aaSamw SIZE, /* c_size_fixed_part */ \ 1785da6c28aaSamw 0, /* c_size_variable_part */ \ 1786da6c28aaSamw }; \ 17878d7e4166Sjose borrego int ndr_##TYPE(struct ndr_reference *ref) { \ 17888d7e4166Sjose borrego return (ndr_basic_integer(ref, SIZE)); \ 1789da6c28aaSamw } 1790da6c28aaSamw 1791da6c28aaSamw #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 17928d7e4166Sjose borrego extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \ 17938d7e4166Sjose borrego ndr_typeinfo_t ndt_s##TYPE = { \ 1794da6c28aaSamw 1, /* NDR version */ \ 1795da6c28aaSamw (SIZE)-1, /* alignment */ \ 1796da6c28aaSamw NDR_F_STRING, /* flags */ \ 17978d7e4166Sjose borrego ndr_s##TYPE, /* ndr_func */ \ 1798da6c28aaSamw 0, /* pdu_size_fixed_part */ \ 1799da6c28aaSamw SIZE, /* pdu_size_variable_part */ \ 1800da6c28aaSamw 0, /* c_size_fixed_part */ \ 1801da6c28aaSamw SIZE, /* c_size_variable_part */ \ 1802da6c28aaSamw }; \ 18038d7e4166Sjose borrego int ndr_s##TYPE(struct ndr_reference *ref) { \ 18048d7e4166Sjose borrego return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \ 1805da6c28aaSamw } 1806da6c28aaSamw 1807da6c28aaSamw #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 1808da6c28aaSamw MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1809da6c28aaSamw MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 1810da6c28aaSamw 18118d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned); 18128d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *); 1813da6c28aaSamw 1814*1ca4e8dfSGordon Ross /* BEGIN CSTYLED */ 18153299f39fSGordon Ross /* Comments to be nice to those searching for these types. */ 18163299f39fSGordon Ross MAKE_BASIC_TYPE(_char, 1) /* ndt__char, ndt_s_char */ 18173299f39fSGordon Ross MAKE_BASIC_TYPE(_uchar, 1) /* ndt__uchar, ndt_s_uchar */ 18183299f39fSGordon Ross MAKE_BASIC_TYPE(_short, 2) /* ndt__short, ndt_s_short */ 18193299f39fSGordon Ross MAKE_BASIC_TYPE(_ushort, 2) /* ndt__ushort, ndt_s_ushort */ 18203299f39fSGordon Ross MAKE_BASIC_TYPE(_long, 4) /* ndt__long, ndt_s_long */ 18213299f39fSGordon Ross MAKE_BASIC_TYPE(_ulong, 4) /* ndt__ulong, ndt_s_ulong */ 1822da6c28aaSamw 18233299f39fSGordon Ross MAKE_BASIC_TYPE_BASE(_wchar, 2) /* ndt__wchar, ndt_s_wchar */ 1824*1ca4e8dfSGordon Ross /* END CSTYLED */ 1825da6c28aaSamw 1826da6c28aaSamw int 18278d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size) 1828da6c28aaSamw { 18293299f39fSGordon Ross ndr_stream_t *nds = ref->stream; 1830*1ca4e8dfSGordon Ross char *valp = (char *)ref->datum; 18318d7e4166Sjose borrego int rc; 1832da6c28aaSamw 18338d7e4166Sjose borrego switch (nds->m_op) { 1834da6c28aaSamw case NDR_M_OP_MARSHALL: 18358d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, ref->pdu_offset, size, 18368d7e4166Sjose borrego valp, nds->swap, ref); 1837da6c28aaSamw break; 1838da6c28aaSamw 1839da6c28aaSamw case NDR_M_OP_UNMARSHALL: 18408d7e4166Sjose borrego rc = NDS_GET_PDU(nds, ref->pdu_offset, size, 18418d7e4166Sjose borrego valp, nds->swap, ref); 1842da6c28aaSamw break; 1843da6c28aaSamw 1844da6c28aaSamw default: 1845da6c28aaSamw NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 1846da6c28aaSamw return (0); 1847da6c28aaSamw } 1848da6c28aaSamw 1849da6c28aaSamw return (rc); 1850da6c28aaSamw } 1851da6c28aaSamw 1852da6c28aaSamw int 18538d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under) 1854da6c28aaSamw { 1855da6c28aaSamw unsigned long pdu_offset = encl_ref->pdu_offset; 1856da6c28aaSamw unsigned size = type_under->pdu_size_fixed_part; 1857da6c28aaSamw char *valp; 18588d7e4166Sjose borrego ndr_ref_t myref; 1859da6c28aaSamw unsigned long i; 1860da6c28aaSamw long sense = 0; 1861da6c28aaSamw char name[30]; 1862da6c28aaSamw 1863da6c28aaSamw assert(size != 0); 1864da6c28aaSamw 1865da6c28aaSamw bzero(&myref, sizeof (myref)); 1866da6c28aaSamw myref.enclosing = encl_ref; 1867da6c28aaSamw myref.stream = encl_ref->stream; 1868da6c28aaSamw myref.packed_alignment = 0; 1869da6c28aaSamw myref.ti = type_under; 1870da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1871da6c28aaSamw myref.name = name; 1872da6c28aaSamw 1873da6c28aaSamw for (i = 0; i < NDR_STRING_MAX; i++) { 18743299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 1875da6c28aaSamw myref.pdu_offset = pdu_offset + i * size; 1876da6c28aaSamw valp = encl_ref->datum + i * size; 1877da6c28aaSamw myref.datum = valp; 1878da6c28aaSamw 18798d7e4166Sjose borrego if (!ndr_inner(&myref)) 1880da6c28aaSamw return (0); 1881da6c28aaSamw 1882da6c28aaSamw switch (size) { 1883da6c28aaSamw case 1: sense = *valp; break; 1884da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1885da6c28aaSamw case 2: sense = *(short *)valp; break; 1886da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1887da6c28aaSamw case 4: sense = *(long *)valp; break; 1888da6c28aaSamw } 1889da6c28aaSamw 1890da6c28aaSamw if (!sense) 1891da6c28aaSamw break; 1892da6c28aaSamw } 1893da6c28aaSamw 1894da6c28aaSamw return (1); 1895da6c28aaSamw } 1896da6c28aaSamw 1897da6c28aaSamw 18988d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref); 18998d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = { 1900da6c28aaSamw 1, /* NDR version */ 1901da6c28aaSamw 2-1, /* alignment */ 1902da6c28aaSamw NDR_F_STRING, /* flags */ 19038d7e4166Sjose borrego ndr_s_wchar, /* ndr_func */ 1904da6c28aaSamw 0, /* pdu_size_fixed_part */ 1905da6c28aaSamw 2, /* pdu_size_variable_part */ 1906da6c28aaSamw 0, /* c_size_fixed_part */ 1907da6c28aaSamw 1, /* c_size_variable_part */ 1908da6c28aaSamw }; 1909da6c28aaSamw 1910da6c28aaSamw 1911da6c28aaSamw /* 1912da6c28aaSamw * Hand coded wchar function because all strings are transported 1913da6c28aaSamw * as wide characters. During NDR_M_OP_MARSHALL, we convert from 1914da6c28aaSamw * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 1915da6c28aaSamw * convert from wide characters to multi-byte. 1916da6c28aaSamw * 19173299f39fSGordon Ross * The most critical thing to get right in this function is to 19183299f39fSGordon Ross * marshall or unmarshall _exactly_ the number of elements the 19193299f39fSGordon Ross * OtW length specifies, as saved by the caller in: strlen_is. 19203299f39fSGordon Ross * Doing otherwise would leave us positioned at the wrong place 19213299f39fSGordon Ross * in the data stream for whatever follows this. Note that the 19223299f39fSGordon Ross * string data covered by strlen_is may or may not include any 19233299f39fSGordon Ross * null termination, but the converted string provided by the 19243299f39fSGordon Ross * caller or returned always has a null terminator. 1925da6c28aaSamw */ 1926da6c28aaSamw int 19278d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref) 1928da6c28aaSamw { 19298d7e4166Sjose borrego ndr_stream_t *nds = encl_ref->stream; 19303299f39fSGordon Ross char *valp = encl_ref->datum; 19318d7e4166Sjose borrego ndr_ref_t myref; 1932da6c28aaSamw char name[30]; 19333299f39fSGordon Ross ndr_wchar_t wcs[NDR_STRING_MAX+1]; 19343299f39fSGordon Ross size_t i, slen, wlen; 19353299f39fSGordon Ross 19363299f39fSGordon Ross /* This is enforced in ndr_outer_string() */ 19373299f39fSGordon Ross assert(encl_ref->strlen_is <= NDR_STRING_MAX); 1938da6c28aaSamw 19398d7e4166Sjose borrego if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1940da6c28aaSamw /* 1941da6c28aaSamw * To avoid problems with zero length strings 1942da6c28aaSamw * we can just null terminate here and be done. 1943da6c28aaSamw */ 1944da6c28aaSamw if (encl_ref->strlen_is == 0) { 1945da6c28aaSamw encl_ref->datum[0] = '\0'; 1946da6c28aaSamw return (1); 1947da6c28aaSamw } 1948da6c28aaSamw } 1949da6c28aaSamw 19503299f39fSGordon Ross /* 19513299f39fSGordon Ross * If we're marshalling, convert the given string 19523299f39fSGordon Ross * from UTF-8 into a local UCS-2 string. 19533299f39fSGordon Ross */ 19543299f39fSGordon Ross if (nds->m_op == NDR_M_OP_MARSHALL) { 19553299f39fSGordon Ross wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX); 19563299f39fSGordon Ross if (wlen == (size_t)-1) 19573299f39fSGordon Ross return (0); 19583299f39fSGordon Ross /* 19593299f39fSGordon Ross * Add a nulls to make strlen_is. 19603299f39fSGordon Ross * (always zero or one of them) 19613299f39fSGordon Ross * Then null terminate at wlen, 19623299f39fSGordon Ross * just for debug convenience. 19633299f39fSGordon Ross */ 19643299f39fSGordon Ross while (wlen < encl_ref->strlen_is) 19653299f39fSGordon Ross wcs[wlen++] = 0; 19663299f39fSGordon Ross wcs[wlen] = 0; 19673299f39fSGordon Ross } 19683299f39fSGordon Ross 19693299f39fSGordon Ross /* 19703299f39fSGordon Ross * Copy wire data to or from the local wc string. 19713299f39fSGordon Ross * Always exactly strlen_is elements. 19723299f39fSGordon Ross */ 1973da6c28aaSamw bzero(&myref, sizeof (myref)); 1974da6c28aaSamw myref.enclosing = encl_ref; 1975da6c28aaSamw myref.stream = encl_ref->stream; 1976da6c28aaSamw myref.packed_alignment = 0; 1977da6c28aaSamw myref.ti = &ndt__wchar; 1978da6c28aaSamw myref.inner_flags = NDR_F_NONE; 1979da6c28aaSamw myref.name = name; 1980da6c28aaSamw myref.pdu_offset = encl_ref->pdu_offset; 19813299f39fSGordon Ross myref.datum = (char *)wcs; 19823299f39fSGordon Ross wlen = encl_ref->strlen_is; 1983da6c28aaSamw 19843299f39fSGordon Ross for (i = 0; i < wlen; i++) { 19853299f39fSGordon Ross (void) snprintf(name, sizeof (name), "[%lu]", i); 19868d7e4166Sjose borrego if (!ndr_inner(&myref)) 1987da6c28aaSamw return (0); 19883299f39fSGordon Ross myref.pdu_offset += sizeof (ndr_wchar_t); 19893299f39fSGordon Ross myref.datum += sizeof (ndr_wchar_t); 19903299f39fSGordon Ross } 1991da6c28aaSamw 19923299f39fSGordon Ross /* 19933299f39fSGordon Ross * If this is unmarshall, convert the local UCS-2 string 19943299f39fSGordon Ross * into a UTF-8 string in the caller's buffer. The caller 19953299f39fSGordon Ross * previously determined the space required and provides a 19963299f39fSGordon Ross * buffer of sufficient size. 19973299f39fSGordon Ross */ 19983299f39fSGordon Ross if (nds->m_op == NDR_M_OP_UNMARSHALL) { 19993299f39fSGordon Ross wcs[wlen] = 0; 2000d1855c81SGordon Ross slen = encl_ref->size_is * NDR_MB_CHAR_MAX; 2001d1855c81SGordon Ross slen = ndr__wcstombs(valp, wcs, slen); 20023299f39fSGordon Ross if (slen == (size_t)-1) 20033299f39fSGordon Ross return (0); 20043299f39fSGordon Ross valp[slen] = '\0'; 2005da6c28aaSamw } 2006da6c28aaSamw 2007da6c28aaSamw return (1); 2008da6c28aaSamw } 200955bf511dSas 201055bf511dSas /* 201155bf511dSas * Converts a multibyte character string to a little-endian, wide-char 201255bf511dSas * string. No more than nwchars wide characters are stored. 201355bf511dSas * A terminating null wide character is appended if there is room. 201455bf511dSas * 201555bf511dSas * Returns the number of wide characters converted, not counting 201655bf511dSas * any terminating null wide character. Returns -1 if an invalid 201755bf511dSas * multibyte character is encountered. 201855bf511dSas */ 20193299f39fSGordon Ross /* ARGSUSED */ 202055bf511dSas size_t 20213299f39fSGordon Ross ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs, 202255bf511dSas size_t nwchars) 202355bf511dSas { 20243299f39fSGordon Ross size_t len; 202555bf511dSas 202655bf511dSas #ifdef _BIG_ENDIAN 20273299f39fSGordon Ross if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) { 20283299f39fSGordon Ross /* Make WC string in LE order. */ 20293299f39fSGordon Ross len = ndr__mbstowcs_le(wcs, mbs, nwchars); 20303299f39fSGordon Ross } else 203155bf511dSas #endif 20323299f39fSGordon Ross len = ndr__mbstowcs(wcs, mbs, nwchars); 203355bf511dSas 20343299f39fSGordon Ross return (len); 203555bf511dSas } 2036