1dc20a302Sas200622 /* 2dc20a302Sas200622 * CDDL HEADER START 3dc20a302Sas200622 * 4dc20a302Sas200622 * The contents of this file are subject to the terms of the 5dc20a302Sas200622 * Common Development and Distribution License (the "License"). 6dc20a302Sas200622 * You may not use this file except in compliance with the License. 7dc20a302Sas200622 * 8dc20a302Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9dc20a302Sas200622 * or http://www.opensolaris.org/os/licensing. 10dc20a302Sas200622 * See the License for the specific language governing permissions 11dc20a302Sas200622 * and limitations under the License. 12dc20a302Sas200622 * 13dc20a302Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14dc20a302Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15dc20a302Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16dc20a302Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17dc20a302Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18dc20a302Sas200622 * 19dc20a302Sas200622 * CDDL HEADER END 20dc20a302Sas200622 */ 21dc20a302Sas200622 /* 22f96bd5c8SAlan Wright * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23dc20a302Sas200622 * Use is subject to license terms. 24*33f5ff17SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 25dc20a302Sas200622 */ 26dc20a302Sas200622 27dc20a302Sas200622 /* 28dc20a302Sas200622 * Network Data Representation (NDR) is a compatible subset of the DCE RPC 29dc20a302Sas200622 * and MSRPC NDR. NDR is used to move parameters consisting of 30dc20a302Sas200622 * complicated trees of data constructs between an RPC client and server. 31dc20a302Sas200622 */ 32dc20a302Sas200622 33dc20a302Sas200622 #include <sys/byteorder.h> 34dc20a302Sas200622 #include <strings.h> 35dc20a302Sas200622 #include <assert.h> 36dc20a302Sas200622 #include <string.h> 37dc20a302Sas200622 #include <stdlib.h> 38dc20a302Sas200622 39dc20a302Sas200622 #include <smbsrv/libsmb.h> 40dc20a302Sas200622 #include <smbsrv/string.h> 418d7e4166Sjose borrego #include <smbsrv/libmlrpc.h> 42dc20a302Sas200622 43f96bd5c8SAlan Wright #define NDR_STRING_MAX 4096 44dc20a302Sas200622 45dc20a302Sas200622 #define NDR_IS_UNION(T) \ 46dc20a302Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION) 47dc20a302Sas200622 #define NDR_IS_STRING(T) \ 48dc20a302Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING) 49dc20a302Sas200622 508d7e4166Sjose borrego extern ndr_typeinfo_t ndt_s_wchar; 51dc20a302Sas200622 52dc20a302Sas200622 /* 53dc20a302Sas200622 * The following synopsis describes the terms TOP-MOST, OUTER and INNER. 54dc20a302Sas200622 * 55dc20a302Sas200622 * Each parameter (call arguments and return values) is a TOP-MOST item. 56dc20a302Sas200622 * A TOP-MOST item consists of one or more OUTER items. An OUTER item 57dc20a302Sas200622 * consists of one or more INNER items. There are important differences 58dc20a302Sas200622 * between each kind, which, primarily, have to do with the allocation 59dc20a302Sas200622 * of memory to contain data structures and the order of processing. 60dc20a302Sas200622 * 61dc20a302Sas200622 * This is most easily demonstrated with a short example. 62dc20a302Sas200622 * Consider these structures: 63dc20a302Sas200622 * 64dc20a302Sas200622 * struct top_param { 65dc20a302Sas200622 * long level; 66dc20a302Sas200622 * struct list * head; 67dc20a302Sas200622 * long count; 68dc20a302Sas200622 * }; 69dc20a302Sas200622 * 70dc20a302Sas200622 * struct list { 71dc20a302Sas200622 * struct list * next; 72dc20a302Sas200622 * char * str; // a string 73dc20a302Sas200622 * }; 74dc20a302Sas200622 * 75dc20a302Sas200622 * Now, consider an instance tree like this: 76dc20a302Sas200622 * 77dc20a302Sas200622 * +---------+ +-------+ +-------+ 78dc20a302Sas200622 * |top_param| +--->|list #1| +--->|list #2| 79dc20a302Sas200622 * +---------+ | +-------+ | +-------+ 80dc20a302Sas200622 * | level | | | next ----+ | next --->(NULL) 81dc20a302Sas200622 * | head ----+ | str -->"foo" | str -->"bar" 82dc20a302Sas200622 * | count | | flag | | flag | 83dc20a302Sas200622 * +---------+ +-------+ +-------+ 84dc20a302Sas200622 * 85dc20a302Sas200622 * The DCE(MS)/RPC Stub Data encoding for the tree is the following. 86dc20a302Sas200622 * The vertical bars (|) indicate OUTER construct boundaries. 87dc20a302Sas200622 * 88dc20a302Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 89dc20a302Sas200622 * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count| 90dc20a302Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 91dc20a302Sas200622 * level |<----------------------- head -------------------------->|count 92dc20a302Sas200622 * TOP TOP TOP 93dc20a302Sas200622 * 94dc20a302Sas200622 * Here's what to notice: 95dc20a302Sas200622 * 96dc20a302Sas200622 * - The members of the TOP-MOST construct are scattered through the Stub 97dc20a302Sas200622 * Data in the order they occur. This example shows a TOP-MOST construct 98dc20a302Sas200622 * consisting of atomic types (pointers and integers). A construct 99dc20a302Sas200622 * (struct) within the TOP-MOST construct would be contiguous and not 100dc20a302Sas200622 * scattered. 101dc20a302Sas200622 * 102dc20a302Sas200622 * - The members of OUTER constructs are contiguous, which allows for 103dc20a302Sas200622 * non-copied relocated (fixed-up) data structures at the packet's 104dc20a302Sas200622 * destination. We don't do fix-ups here. The pointers within the 105dc20a302Sas200622 * OUTER constructs are processed depth-first in the order that they 106dc20a302Sas200622 * occur. If they were processed breadth first, the sequence would 107dc20a302Sas200622 * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may 108dc20a302Sas200622 * be variable length, and pointers are often encountered before the 109dc20a302Sas200622 * size(s) is known. 110dc20a302Sas200622 * 111dc20a302Sas200622 * - The INNER constructs are simply the members of an OUTER construct. 112dc20a302Sas200622 * 113dc20a302Sas200622 * For comparison, consider how ONC RPC would handle the same tree of 114dc20a302Sas200622 * data. ONC requires very little buffering, while DCE requires enough 115dc20a302Sas200622 * buffer space for the entire message. ONC does atom-by-atom depth-first 116dc20a302Sas200622 * (de)serialization and copy, while DCE allows for constructs to be 117dc20a302Sas200622 * "fixed-up" (relocated) in place at the destination. The packet data 118dc20a302Sas200622 * for the same tree processed by ONC RPC would look like this: 119dc20a302Sas200622 * 120dc20a302Sas200622 * +---------------------------------------------------------------------+ 121dc20a302Sas200622 * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count| 122dc20a302Sas200622 * +---------------------------------------------------------------------+ 123dc20a302Sas200622 * TOP #1 #2 #2 bar #2 #1 foo #1 TOP 124dc20a302Sas200622 * 125dc20a302Sas200622 * More details about each TOP-MOST, OUTER, and INNER constructs appear 126dc20a302Sas200622 * throughout this source file near where such constructs are processed. 127dc20a302Sas200622 * 128dc20a302Sas200622 * NDR_REFERENCE 129dc20a302Sas200622 * 1308d7e4166Sjose borrego * The primary object for NDR is the ndr_ref_t. 131dc20a302Sas200622 * 1328d7e4166Sjose borrego * An ndr reference indicates the local datum (i.e. native "C" data 133dc20a302Sas200622 * format), and the element within the Stub Data (contained within the 1348d7e4166Sjose borrego * RPC PDU (protocol data unit). An ndr reference also indicates, 135dc20a302Sas200622 * largely as a debugging aid, something about the type of the 136dc20a302Sas200622 * 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 139dc20a302Sas200622 * order of the call graph. 140dc20a302Sas200622 * 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 143dc20a302Sas200622 * where in the Stub Data the value is to be stored/retrieved. 144dc20a302Sas200622 * 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 148dc20a302Sas200622 * indicates the arm of a union to use. 149dc20a302Sas200622 * 150dc20a302Sas200622 * QUEUE OF OUTER REFERENCES 151dc20a302Sas200622 * 152dc20a302Sas200622 * Some OUTER constructs are variable size. Sometimes (often) we don't 153dc20a302Sas200622 * know the size of the OUTER construct until after pointers have been 154dc20a302Sas200622 * encountered. Hence, we can not begin processing the referent of the 155dc20a302Sas200622 * pointer until after the referring OUTER construct is completely 156dc20a302Sas200622 * processed, i.e. we don't know where to find/put the referent in the 157dc20a302Sas200622 * Stub Data until we know the size of all its predecessors. 158dc20a302Sas200622 * 159dc20a302Sas200622 * 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. 163dc20a302Sas200622 * 164dc20a302Sas200622 * Refer to the example above as we illustrate the queue here. In these 165dc20a302Sas200622 * illustrations, the queue entries are not the data structures themselves. 1668d7e4166Sjose borrego * Rather, they are ndr-reference entries which **refer** to the data 167dc20a302Sas200622 * structures in both the PDU and local memory. 168dc20a302Sas200622 * 169dc20a302Sas200622 * During some point in the processing, the queue looks like this: 170dc20a302Sas200622 * 171dc20a302Sas200622 * outer_current -------v 172dc20a302Sas200622 * outer_queue_head --> list#1 --0 173dc20a302Sas200622 * outer_queue_tailp ---------& 174dc20a302Sas200622 * 175dc20a302Sas200622 * When the pointer #1.next is encountered, and entry is added to the 176dc20a302Sas200622 * queue, 177dc20a302Sas200622 * 178dc20a302Sas200622 * outer_current -------v 179dc20a302Sas200622 * outer_queue_head --> list#1 --> list#2 --0 180dc20a302Sas200622 * outer_queue_tailp --------------------& 181dc20a302Sas200622 * 182dc20a302Sas200622 * and the members of #1 continue to be processed, which encounters 183dc20a302Sas200622 * #1.str: 184dc20a302Sas200622 * 185dc20a302Sas200622 * outer_current -------v 186dc20a302Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 187dc20a302Sas200622 * outer_queue_tailp ------------------------------& 188dc20a302Sas200622 * 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: 191dc20a302Sas200622 * 192dc20a302Sas200622 * outer_current ------------------v 193dc20a302Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 194dc20a302Sas200622 * outer_queue_tailp --------------------& 195dc20a302Sas200622 * 196dc20a302Sas200622 * Space for list#2 is allocated, either in the Stub Data or of local 197dc20a302Sas200622 * memory. When #2.next is encountered, it is found to be the null 198dc20a302Sas200622 * pointer and no reference is added to the queue. When #2.str is 199dc20a302Sas200622 * encountered, it is found to be valid, and a reference is added: 200dc20a302Sas200622 * 201dc20a302Sas200622 * outer_current ------------------v 202dc20a302Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 203dc20a302Sas200622 * outer_queue_tailp ------------------------------& 204dc20a302Sas200622 * 205dc20a302Sas200622 * Processing continues in a similar fashion with the string "bar", 206dc20a302Sas200622 * which is variable-length. At this point, memory for "bar" may be 207dc20a302Sas200622 * malloc()ed during NDR_M_OP_UNMARSHALL: 208dc20a302Sas200622 * 209dc20a302Sas200622 * outer_current -----------------------------v 210dc20a302Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 211dc20a302Sas200622 * outer_queue_tailp ------------------------------& 212dc20a302Sas200622 * 213dc20a302Sas200622 * And finishes on string "foo". Notice that because "bar" is a 214dc20a302Sas200622 * variable length string, and we don't know the PDU offset for "foo" 215dc20a302Sas200622 * until we reach this point. 216dc20a302Sas200622 * 217dc20a302Sas200622 * When the queue is drained (current->next==0), processing continues 218dc20a302Sas200622 * with the next TOP-MOST member. 219dc20a302Sas200622 * 220dc20a302Sas200622 * The queue of OUTER constructs manages the variable-length semantics 221dc20a302Sas200622 * of OUTER constructs and satisfies the depth-first requirement. 222dc20a302Sas200622 * We allow the queue to linger until the entire TOP-MOST structure is 223dc20a302Sas200622 * processed as an aid to debugging. 224dc20a302Sas200622 */ 225dc20a302Sas200622 2268d7e4166Sjose borrego static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *); 2278d7e4166Sjose borrego extern int ndr__ulong(ndr_ref_t *); 228dc20a302Sas200622 229dc20a302Sas200622 /* 230dc20a302Sas200622 * TOP-MOST ELEMENTS 231dc20a302Sas200622 * 232dc20a302Sas200622 * This is fundamentally the first OUTER construct of the parameter, 233dc20a302Sas200622 * possibly followed by more OUTER constructs due to pointers. The 234dc20a302Sas200622 * datum (local memory) for TOP-MOST constructs (structs) is allocated 235dc20a302Sas200622 * by the caller of NDR. 236dc20a302Sas200622 * 237dc20a302Sas200622 * After the element is transferred, the outer_queue is drained. 238dc20a302Sas200622 * 239dc20a302Sas200622 * All we have to do is add an entry to the outer_queue for this 240dc20a302Sas200622 * top-most member, and commence the outer_queue processing. 241dc20a302Sas200622 */ 242dc20a302Sas200622 int 2438d7e4166Sjose borrego ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum) 244dc20a302Sas200622 { 2458d7e4166Sjose borrego ndr_ref_t myref; 246dc20a302Sas200622 247dc20a302Sas200622 bzero(&myref, sizeof (myref)); 2488d7e4166Sjose borrego myref.stream = nds; 249dc20a302Sas200622 myref.datum = datum; 250dc20a302Sas200622 myref.name = "PROCESS"; 251dc20a302Sas200622 myref.ti = ti; 252dc20a302Sas200622 2538d7e4166Sjose borrego return (ndr_topmost(&myref)); 254dc20a302Sas200622 } 255dc20a302Sas200622 256dc20a302Sas200622 int 2578d7e4166Sjose borrego ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum) 258dc20a302Sas200622 { 2598d7e4166Sjose borrego ndr_ref_t myref; 260dc20a302Sas200622 261dc20a302Sas200622 bzero(&myref, sizeof (myref)); 2628d7e4166Sjose borrego myref.stream = nds; 263dc20a302Sas200622 myref.datum = datum; 264dc20a302Sas200622 myref.name = "OPERATION"; 265dc20a302Sas200622 myref.ti = ti; 266dc20a302Sas200622 myref.inner_flags = NDR_F_SWITCH_IS; 267dc20a302Sas200622 myref.switch_is = opnum; 268dc20a302Sas200622 269dc20a302Sas200622 if (ti->type_flags != NDR_F_INTERFACE) { 270dc20a302Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE); 271dc20a302Sas200622 return (0); 272dc20a302Sas200622 } 273dc20a302Sas200622 274dc20a302Sas200622 return ((*ti->ndr_func)(&myref)); 275dc20a302Sas200622 } 276dc20a302Sas200622 277dc20a302Sas200622 int 2788d7e4166Sjose borrego ndr_params(ndr_ref_t *params_ref) 279dc20a302Sas200622 { 2808d7e4166Sjose borrego ndr_typeinfo_t *ti = params_ref->ti; 281dc20a302Sas200622 282dc20a302Sas200622 if (ti->type_flags == NDR_F_OPERATION) 283dc20a302Sas200622 return (*ti->ndr_func) (params_ref); 284dc20a302Sas200622 else 2858d7e4166Sjose borrego return (ndr_topmost(params_ref)); 286dc20a302Sas200622 } 287dc20a302Sas200622 288dc20a302Sas200622 int 2898d7e4166Sjose borrego ndr_topmost(ndr_ref_t *top_ref) 290dc20a302Sas200622 { 2918d7e4166Sjose borrego ndr_stream_t *nds; 2928d7e4166Sjose borrego ndr_typeinfo_t *ti; 2938d7e4166Sjose borrego ndr_ref_t *outer_ref = 0; 294dc20a302Sas200622 int is_varlen; 295dc20a302Sas200622 int is_string; 296dc20a302Sas200622 int error; 297dc20a302Sas200622 int rc; 298dc20a302Sas200622 unsigned n_fixed; 299dc20a302Sas200622 int params; 300dc20a302Sas200622 301dc20a302Sas200622 assert(top_ref); 302dc20a302Sas200622 assert(top_ref->stream); 303dc20a302Sas200622 assert(top_ref->ti); 304dc20a302Sas200622 3058d7e4166Sjose borrego nds = top_ref->stream; 306dc20a302Sas200622 ti = top_ref->ti; 307dc20a302Sas200622 308dc20a302Sas200622 is_varlen = ti->pdu_size_variable_part; 309dc20a302Sas200622 is_string = NDR_IS_STRING(ti); 310dc20a302Sas200622 3118d7e4166Sjose borrego assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp); 3128d7e4166Sjose borrego assert(!nds->outer_current); 313dc20a302Sas200622 314dc20a302Sas200622 params = top_ref->inner_flags & NDR_F_PARAMS_MASK; 315dc20a302Sas200622 316dc20a302Sas200622 switch (params) { 317dc20a302Sas200622 case NDR_F_NONE: 318dc20a302Sas200622 case NDR_F_SWITCH_IS: 319dc20a302Sas200622 if (is_string || is_varlen) { 320dc20a302Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 321dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 322dc20a302Sas200622 return (0); 323dc20a302Sas200622 } 324dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part; 325dc20a302Sas200622 break; 326dc20a302Sas200622 327dc20a302Sas200622 case NDR_F_SIZE_IS: 328dc20a302Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 329dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 330dc20a302Sas200622 return (0); 331dc20a302Sas200622 332dc20a302Sas200622 case NDR_F_DIMENSION_IS: 333dc20a302Sas200622 if (is_varlen) { 334dc20a302Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 335dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 336dc20a302Sas200622 return (0); 337dc20a302Sas200622 } 338dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is; 339dc20a302Sas200622 break; 340dc20a302Sas200622 341dc20a302Sas200622 case NDR_F_IS_POINTER: 342dc20a302Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 343dc20a302Sas200622 n_fixed = 4; 344dc20a302Sas200622 break; 345dc20a302Sas200622 346dc20a302Sas200622 case NDR_F_IS_REFERENCE: 347dc20a302Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 348dc20a302Sas200622 n_fixed = 0; 349dc20a302Sas200622 break; 350dc20a302Sas200622 351dc20a302Sas200622 default: 352dc20a302Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 353dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 354dc20a302Sas200622 return (0); 355dc20a302Sas200622 } 356dc20a302Sas200622 3578d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(top_ref); 358dc20a302Sas200622 if (!outer_ref) 359dc20a302Sas200622 return (0); /* error already set */ 360dc20a302Sas200622 361dc20a302Sas200622 /* 362dc20a302Sas200622 * 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 365dc20a302Sas200622 * the construct, and we already have the memory. 366dc20a302Sas200622 */ 367dc20a302Sas200622 368dc20a302Sas200622 /* move the flags, etc, around again, undoes enter_outer_queue() */ 369dc20a302Sas200622 outer_ref->inner_flags = top_ref->inner_flags; 370dc20a302Sas200622 outer_ref->outer_flags = 0; 371dc20a302Sas200622 outer_ref->datum = top_ref->datum; 372dc20a302Sas200622 373dc20a302Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 3748d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 375dc20a302Sas200622 return (0); /* error already set */ 376dc20a302Sas200622 377dc20a302Sas200622 /* Regardless of what it is, this is where it starts */ 3788d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 379dc20a302Sas200622 3808d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_fixed); 381dc20a302Sas200622 if (!rc) 382dc20a302Sas200622 return (0); /* error already set */ 383dc20a302Sas200622 384dc20a302Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed; 385dc20a302Sas200622 386dc20a302Sas200622 /* 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; 390dc20a302Sas200622 391dc20a302Sas200622 /* do the topmost member */ 3928d7e4166Sjose borrego rc = ndr_inner(outer_ref); 393dc20a302Sas200622 if (!rc) 394dc20a302Sas200622 return (0); /* error already set */ 395dc20a302Sas200622 3968d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 397dc20a302Sas200622 398dc20a302Sas200622 /* 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)); 401dc20a302Sas200622 } 402dc20a302Sas200622 4038d7e4166Sjose borrego static ndr_ref_t * 4048d7e4166Sjose borrego ndr_enter_outer_queue(ndr_ref_t *arg_ref) 405dc20a302Sas200622 { 4068d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 4078d7e4166Sjose borrego ndr_ref_t *outer_ref; 408dc20a302Sas200622 409dc20a302Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 4108d7e4166Sjose borrego outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref); 411dc20a302Sas200622 if (!outer_ref) { 412dc20a302Sas200622 NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED); 413dc20a302Sas200622 return (0); 414dc20a302Sas200622 } 415dc20a302Sas200622 416dc20a302Sas200622 *outer_ref = *arg_ref; 417dc20a302Sas200622 418dc20a302Sas200622 /* move advice in inner_flags to outer_flags */ 419dc20a302Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 420dc20a302Sas200622 outer_ref->inner_flags = 0; 4218d7e4166Sjose borrego outer_ref->enclosing = nds->outer_current; 422dc20a302Sas200622 outer_ref->backptr = 0; 423dc20a302Sas200622 outer_ref->datum = 0; 424dc20a302Sas200622 4258d7e4166Sjose borrego assert(nds->outer_queue_tailp); 426dc20a302Sas200622 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; 430dc20a302Sas200622 return (outer_ref); 431dc20a302Sas200622 } 432dc20a302Sas200622 433dc20a302Sas200622 int 4348d7e4166Sjose borrego ndr_run_outer_queue(ndr_stream_t *nds) 435dc20a302Sas200622 { 4368d7e4166Sjose borrego while (nds->outer_current) { 4378d7e4166Sjose borrego nds->outer_queue_tailp = &nds->outer_current->next; 438dc20a302Sas200622 4398d7e4166Sjose borrego if (!ndr_outer(nds->outer_current)) 440dc20a302Sas200622 return (0); 441dc20a302Sas200622 4428d7e4166Sjose borrego nds->outer_current = nds->outer_current->next; 443dc20a302Sas200622 } 444dc20a302Sas200622 445dc20a302Sas200622 return (1); 446dc20a302Sas200622 } 447dc20a302Sas200622 448dc20a302Sas200622 /* 449dc20a302Sas200622 * OUTER CONSTRUCTS 450dc20a302Sas200622 * 451dc20a302Sas200622 * OUTER constructs are where the real work is, which stems from the 452dc20a302Sas200622 * variable-length potential. 453dc20a302Sas200622 * 454dc20a302Sas200622 * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT 455dc20a302Sas200622 * 456dc20a302Sas200622 * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT, 457dc20a302Sas200622 * VARYING, and VARYING/CONFORMANT. 458dc20a302Sas200622 * 459dc20a302Sas200622 * What makes this so tough is that the variable-length array may be well 460dc20a302Sas200622 * encapsulated within the outer construct. Further, because DCE(MS)/RPC 461dc20a302Sas200622 * tries to keep the constructs contiguous in the data stream, the sizing 462dc20a302Sas200622 * information precedes the entire OUTER construct. The sizing information 463dc20a302Sas200622 * must be used at the appropriate time, which can be after many, many, 464dc20a302Sas200622 * many fixed-length elements. During IDL type analysis, we know in 465dc20a302Sas200622 * advance constructs that encapsulate variable-length constructs. So, 466dc20a302Sas200622 * we know when we have a sizing header and when we don't. The actual 467dc20a302Sas200622 * semantics of the header are largely deferred. 468dc20a302Sas200622 * 469dc20a302Sas200622 * Currently, VARYING constructs are not implemented but they are described 470dc20a302Sas200622 * here in case they have to be implemented in the future. Similarly, 471dc20a302Sas200622 * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently 472dc20a302Sas200622 * not implemented. Only one-dimensional, variable-length arrays are 473dc20a302Sas200622 * supported. 474dc20a302Sas200622 * 475dc20a302Sas200622 * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW 476dc20a302Sas200622 * 477dc20a302Sas200622 * All variable-length values are arrays. These arrays may be embedded 478dc20a302Sas200622 * well within another construct. However, a variable-length construct 479dc20a302Sas200622 * may ONLY appear as the last member of an enclosing construct. Example: 480dc20a302Sas200622 * 481dc20a302Sas200622 * struct credentials { 482dc20a302Sas200622 * ulong uid, gid; 483dc20a302Sas200622 * ulong n_gids; 484dc20a302Sas200622 * [size_is(n_gids)] 485dc20a302Sas200622 * ulong gids[*]; // variable-length. 486dc20a302Sas200622 * }; 487dc20a302Sas200622 * 488dc20a302Sas200622 * CONFORMANT constructs have a dynamic size in local memory and in the 489dc20a302Sas200622 * PDU. The CONFORMANT quality is indicated by the [size_is()] advice. 490dc20a302Sas200622 * CONFORMANT constructs have the following header: 491dc20a302Sas200622 * 492dc20a302Sas200622 * struct conformant_header { 493dc20a302Sas200622 * ulong size_is; 494dc20a302Sas200622 * }; 495dc20a302Sas200622 * 496dc20a302Sas200622 * (Multi-dimensional CONFORMANT arrays have a similar header for each 497dc20a302Sas200622 * dimension - not implemented). 498dc20a302Sas200622 * 499dc20a302Sas200622 * Example CONFORMANT construct: 500dc20a302Sas200622 * 501dc20a302Sas200622 * struct user { 502dc20a302Sas200622 * char * name; 503dc20a302Sas200622 * struct credentials cred; // see above 504dc20a302Sas200622 * }; 505dc20a302Sas200622 * 506dc20a302Sas200622 * Consider the data tree: 507dc20a302Sas200622 * 508dc20a302Sas200622 * +--------+ 509dc20a302Sas200622 * | user | 510dc20a302Sas200622 * +--------+ 511dc20a302Sas200622 * | name ----> "fred" (the string is a different OUTER) 512dc20a302Sas200622 * | uid | 513dc20a302Sas200622 * | gid | 514dc20a302Sas200622 * | n_gids | for example, 3 515dc20a302Sas200622 * | gids[0]| 516dc20a302Sas200622 * | gids[1]| 517dc20a302Sas200622 * | gids[2]| 518dc20a302Sas200622 * +--------+ 519dc20a302Sas200622 * 520dc20a302Sas200622 * The OUTER construct in the Stub Data would be: 521dc20a302Sas200622 * 522dc20a302Sas200622 * +---+---------+---------------------------------------------+ 523dc20a302Sas200622 * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]| 524dc20a302Sas200622 * +---+---------+---------------------------------------------+ 525dc20a302Sas200622 * szing hdr|user |<-------------- user.cred ------------>| 526dc20a302Sas200622 * |<--- fixed-size ---->|<----- conformant ---->| 527dc20a302Sas200622 * 528dc20a302Sas200622 * The ndr_typeinfo for struct user will have: 529dc20a302Sas200622 * pdu_fixed_size_part = 16 four long words (name uid gid n_gids) 530dc20a302Sas200622 * pdu_variable_size_part = 4 per element, sizeof gids[0] 531dc20a302Sas200622 * 532dc20a302Sas200622 * VARYING CONSTRUCTS -- NOT IMPLEMENTED 533dc20a302Sas200622 * 534dc20a302Sas200622 * VARYING constructs have the following header: 535dc20a302Sas200622 * 536dc20a302Sas200622 * struct varying_header { 537dc20a302Sas200622 * ulong first_is; 538dc20a302Sas200622 * ulong length_is; 539dc20a302Sas200622 * }; 540dc20a302Sas200622 * 541dc20a302Sas200622 * This indicates which interval of an array is significant. 542dc20a302Sas200622 * Non-intersecting elements of the array are undefined and usually 543dc20a302Sas200622 * zero-filled. The first_is parameter for C arrays is always 0 for 544dc20a302Sas200622 * the first element. 545dc20a302Sas200622 * 546dc20a302Sas200622 * N.B. Constructs may contain one CONFORMANT element, which is always 547dc20a302Sas200622 * last, but may contain many VARYING elements, which can be anywhere. 548dc20a302Sas200622 * 549dc20a302Sas200622 * VARYING CONFORMANT constructs have the sizing headers arranged like 550dc20a302Sas200622 * this: 551dc20a302Sas200622 * 552dc20a302Sas200622 * struct conformant_header all_conformant[N_CONFORMANT_DIM]; 553dc20a302Sas200622 * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS]; 554dc20a302Sas200622 * 555dc20a302Sas200622 * The sizing header is immediately followed by the values for the 556dc20a302Sas200622 * construct. Again, we don't support more than one dimension and 557dc20a302Sas200622 * we don't support VARYING constructs at this time. 558dc20a302Sas200622 * 559dc20a302Sas200622 * A good example of a VARYING/CONFORMANT data structure is the UNIX 560dc20a302Sas200622 * directory entry: 561dc20a302Sas200622 * 562dc20a302Sas200622 * struct dirent { 563dc20a302Sas200622 * ushort reclen; 564dc20a302Sas200622 * ushort namlen; 565dc20a302Sas200622 * ulong inum; 566dc20a302Sas200622 * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL 567dc20a302Sas200622 * uchar name[*]; 568dc20a302Sas200622 * }; 569dc20a302Sas200622 * 570dc20a302Sas200622 * 571dc20a302Sas200622 * STRINGS ARE A SPECIAL CASE 572dc20a302Sas200622 * 573dc20a302Sas200622 * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures 574dc20a302Sas200622 * for strings. This is a simple one-dimensional variable-length array, 575dc20a302Sas200622 * typically with its last element all zeroes. We handle strings with the 576dc20a302Sas200622 * header: 577dc20a302Sas200622 * 578dc20a302Sas200622 * struct string_header { 579dc20a302Sas200622 * ulong size_is; 580dc20a302Sas200622 * ulong first_is; // always 0 581dc20a302Sas200622 * ulong length_is; // always same as size_is 582dc20a302Sas200622 * }; 583dc20a302Sas200622 * 584dc20a302Sas200622 * If general support for VARYING and VARYING/CONFORMANT mechanisms is 585dc20a302Sas200622 * implemented, we probably won't need the strings special case. 586dc20a302Sas200622 */ 587dc20a302Sas200622 int 5888d7e4166Sjose borrego ndr_outer(ndr_ref_t *outer_ref) 589dc20a302Sas200622 { 5908d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 5918d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 592dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 593dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 594dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 595dc20a302Sas200622 int error = NDR_ERR_OUTER_PARAMS_BAD; 596dc20a302Sas200622 int params; 597dc20a302Sas200622 598dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 599dc20a302Sas200622 600dc20a302Sas200622 NDR_TATTLE(outer_ref, "--OUTER--"); 601dc20a302Sas200622 602dc20a302Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 6038d7e4166Sjose borrego if (!ndr_outer_align(outer_ref)) 604dc20a302Sas200622 return (0); /* error already set */ 605dc20a302Sas200622 606dc20a302Sas200622 /* Regardless of what it is, this is where it starts */ 6078d7e4166Sjose borrego outer_ref->pdu_offset = nds->pdu_scan_offset; 608dc20a302Sas200622 609dc20a302Sas200622 if (is_union) { 610dc20a302Sas200622 error = NDR_ERR_OUTER_UNION_ILLEGAL; 611dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 612dc20a302Sas200622 return (0); 613dc20a302Sas200622 } 614dc20a302Sas200622 615dc20a302Sas200622 switch (params) { 616dc20a302Sas200622 case NDR_F_NONE: 617dc20a302Sas200622 if (is_string) 6188d7e4166Sjose borrego return (ndr_outer_string(outer_ref)); 619dc20a302Sas200622 if (is_varlen) 6208d7e4166Sjose borrego return (ndr_outer_conformant_construct(outer_ref)); 621dc20a302Sas200622 6228d7e4166Sjose borrego return (ndr_outer_fixed(outer_ref)); 623dc20a302Sas200622 624dc20a302Sas200622 case NDR_F_SIZE_IS: 625dc20a302Sas200622 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: 628dc20a302Sas200622 if (is_varlen) { 629dc20a302Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 630dc20a302Sas200622 break; 631dc20a302Sas200622 } 632dc20a302Sas200622 633f96bd5c8SAlan Wright if (params & NDR_F_SIZE_IS) 6348d7e4166Sjose borrego return (ndr_outer_conformant_array(outer_ref)); 635dc20a302Sas200622 else 6368d7e4166Sjose borrego return (ndr_outer_fixed_array(outer_ref)); 637dc20a302Sas200622 638dc20a302Sas200622 default: 639dc20a302Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 640dc20a302Sas200622 break; 641dc20a302Sas200622 } 642dc20a302Sas200622 643dc20a302Sas200622 /* 644dc20a302Sas200622 * If we get here, something is wrong. Most likely, 645dc20a302Sas200622 * the params flags do not match. 646dc20a302Sas200622 */ 647dc20a302Sas200622 NDR_SET_ERROR(outer_ref, error); 648dc20a302Sas200622 return (0); 649dc20a302Sas200622 } 650dc20a302Sas200622 651dc20a302Sas200622 int 6528d7e4166Sjose borrego ndr_outer_fixed(ndr_ref_t *outer_ref) 653dc20a302Sas200622 { 6548d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 6558d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 6568d7e4166Sjose borrego ndr_ref_t myref; 657dc20a302Sas200622 char *valp = NULL; 658dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 659dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 660dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 661dc20a302Sas200622 int rc; 662dc20a302Sas200622 unsigned n_hdr; 663dc20a302Sas200622 unsigned n_fixed; 664dc20a302Sas200622 unsigned n_variable; 665dc20a302Sas200622 unsigned n_alloc; 666dc20a302Sas200622 unsigned n_pdu_total; 667dc20a302Sas200622 int params; 668dc20a302Sas200622 669dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 670dc20a302Sas200622 671dc20a302Sas200622 assert(!is_varlen && !is_string && !is_union); 672dc20a302Sas200622 assert(params == NDR_F_NONE); 673dc20a302Sas200622 674dc20a302Sas200622 /* no header for this */ 675dc20a302Sas200622 n_hdr = 0; 676dc20a302Sas200622 677dc20a302Sas200622 /* fixed part -- exactly one of these */ 678dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part; 679dc20a302Sas200622 assert(n_fixed > 0); 680dc20a302Sas200622 681dc20a302Sas200622 /* variable part -- exactly none of these */ 682dc20a302Sas200622 n_variable = 0; 683dc20a302Sas200622 684dc20a302Sas200622 /* sum them up to determine the PDU space required */ 685dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 686dc20a302Sas200622 687dc20a302Sas200622 /* similar sum to determine how much local memory is required */ 688dc20a302Sas200622 n_alloc = n_fixed + n_variable; 689dc20a302Sas200622 6908d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 691dc20a302Sas200622 if (!rc) 692dc20a302Sas200622 return (rc); /* error already set */ 693dc20a302Sas200622 6948d7e4166Sjose borrego switch (nds->m_op) { 695dc20a302Sas200622 case NDR_M_OP_MARSHALL: 696dc20a302Sas200622 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) 702dc20a302Sas200622 assert(valp == *outer_ref->backptr); 703dc20a302Sas200622 break; 704dc20a302Sas200622 705dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 7068d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 707dc20a302Sas200622 if (!valp) { 708dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 709dc20a302Sas200622 return (0); 710dc20a302Sas200622 } 711dc20a302Sas200622 if (outer_ref->backptr) 712dc20a302Sas200622 *outer_ref->backptr = valp; 713dc20a302Sas200622 outer_ref->datum = valp; 714dc20a302Sas200622 break; 715dc20a302Sas200622 716dc20a302Sas200622 default: 717dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 718dc20a302Sas200622 return (0); 719dc20a302Sas200622 } 720dc20a302Sas200622 721dc20a302Sas200622 bzero(&myref, sizeof (myref)); 7228d7e4166Sjose borrego myref.stream = nds; 723dc20a302Sas200622 myref.enclosing = outer_ref; 724dc20a302Sas200622 myref.ti = outer_ref->ti; 725dc20a302Sas200622 myref.datum = outer_ref->datum; 726dc20a302Sas200622 myref.name = "FIXED-VALUE"; 727dc20a302Sas200622 myref.outer_flags = NDR_F_NONE; 728dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 729dc20a302Sas200622 730dc20a302Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 731dc20a302Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 732dc20a302Sas200622 7338d7e4166Sjose borrego rc = ndr_inner(&myref); 734dc20a302Sas200622 if (!rc) 735dc20a302Sas200622 return (rc); /* error already set */ 736dc20a302Sas200622 7378d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 738dc20a302Sas200622 return (1); 739dc20a302Sas200622 } 740dc20a302Sas200622 741dc20a302Sas200622 int 7428d7e4166Sjose borrego ndr_outer_fixed_array(ndr_ref_t *outer_ref) 743dc20a302Sas200622 { 7448d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 7458d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 7468d7e4166Sjose borrego ndr_ref_t myref; 747dc20a302Sas200622 char *valp = NULL; 748dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 749dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 750dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 751dc20a302Sas200622 int rc; 752dc20a302Sas200622 unsigned n_hdr; 753dc20a302Sas200622 unsigned n_fixed; 754dc20a302Sas200622 unsigned n_variable; 755dc20a302Sas200622 unsigned n_alloc; 756dc20a302Sas200622 unsigned n_pdu_total; 757dc20a302Sas200622 int params; 758dc20a302Sas200622 759dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 760dc20a302Sas200622 761dc20a302Sas200622 assert(!is_varlen && !is_string && !is_union); 762dc20a302Sas200622 assert(params == NDR_F_DIMENSION_IS); 763dc20a302Sas200622 764dc20a302Sas200622 /* no header for this */ 765dc20a302Sas200622 n_hdr = 0; 766dc20a302Sas200622 767dc20a302Sas200622 /* fixed part -- exactly dimension_is of these */ 768dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 769dc20a302Sas200622 assert(n_fixed > 0); 770dc20a302Sas200622 771dc20a302Sas200622 /* variable part -- exactly none of these */ 772dc20a302Sas200622 n_variable = 0; 773dc20a302Sas200622 774dc20a302Sas200622 /* sum them up to determine the PDU space required */ 775dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 776dc20a302Sas200622 777dc20a302Sas200622 /* similar sum to determine how much local memory is required */ 778dc20a302Sas200622 n_alloc = n_fixed + n_variable; 779dc20a302Sas200622 7808d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 781dc20a302Sas200622 if (!rc) 782dc20a302Sas200622 return (rc); /* error already set */ 783dc20a302Sas200622 7848d7e4166Sjose borrego switch (nds->m_op) { 785dc20a302Sas200622 case NDR_M_OP_MARSHALL: 786dc20a302Sas200622 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) 792dc20a302Sas200622 assert(valp == *outer_ref->backptr); 793dc20a302Sas200622 break; 794dc20a302Sas200622 795dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 7968d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 797dc20a302Sas200622 if (!valp) { 798dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 799dc20a302Sas200622 return (0); 800dc20a302Sas200622 } 801dc20a302Sas200622 if (outer_ref->backptr) 802dc20a302Sas200622 *outer_ref->backptr = valp; 803dc20a302Sas200622 outer_ref->datum = valp; 804dc20a302Sas200622 break; 805dc20a302Sas200622 806dc20a302Sas200622 default: 807dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 808dc20a302Sas200622 return (0); 809dc20a302Sas200622 } 810dc20a302Sas200622 811dc20a302Sas200622 bzero(&myref, sizeof (myref)); 8128d7e4166Sjose borrego myref.stream = nds; 813dc20a302Sas200622 myref.enclosing = outer_ref; 814dc20a302Sas200622 myref.ti = outer_ref->ti; 815dc20a302Sas200622 myref.datum = outer_ref->datum; 816dc20a302Sas200622 myref.name = "FIXED-ARRAY"; 817dc20a302Sas200622 myref.outer_flags = NDR_F_NONE; 818dc20a302Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS; 819dc20a302Sas200622 myref.dimension_is = outer_ref->dimension_is; 820dc20a302Sas200622 821dc20a302Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 822dc20a302Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 823dc20a302Sas200622 8248d7e4166Sjose borrego rc = ndr_inner(&myref); 825dc20a302Sas200622 if (!rc) 826dc20a302Sas200622 return (rc); /* error already set */ 827dc20a302Sas200622 8288d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 829dc20a302Sas200622 return (1); 830dc20a302Sas200622 } 831dc20a302Sas200622 832dc20a302Sas200622 int 8338d7e4166Sjose borrego ndr_outer_conformant_array(ndr_ref_t *outer_ref) 834dc20a302Sas200622 { 8358d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 8368d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 8378d7e4166Sjose borrego ndr_ref_t myref; 838dc20a302Sas200622 char *valp = NULL; 839dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 840dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 841dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 842dc20a302Sas200622 unsigned long size_is; 843dc20a302Sas200622 int rc; 844dc20a302Sas200622 unsigned n_hdr; 845dc20a302Sas200622 unsigned n_fixed; 846dc20a302Sas200622 unsigned n_variable; 847dc20a302Sas200622 unsigned n_alloc; 848dc20a302Sas200622 unsigned n_pdu_total; 849f96bd5c8SAlan Wright unsigned n_ptr_offset; 850dc20a302Sas200622 int params; 851dc20a302Sas200622 852dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 853dc20a302Sas200622 854dc20a302Sas200622 assert(!is_varlen && !is_string && !is_union); 855f96bd5c8SAlan Wright assert(params & NDR_F_SIZE_IS); 856dc20a302Sas200622 857dc20a302Sas200622 /* conformant header for this */ 858dc20a302Sas200622 n_hdr = 4; 859dc20a302Sas200622 860dc20a302Sas200622 /* fixed part -- exactly none of these */ 861dc20a302Sas200622 n_fixed = 0; 862dc20a302Sas200622 863dc20a302Sas200622 /* variable part -- exactly size_of of these */ 864dc20a302Sas200622 /* notice that it is the **fixed** size of the ti */ 865dc20a302Sas200622 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 866dc20a302Sas200622 867dc20a302Sas200622 /* sum them up to determine the PDU space required */ 868dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 869dc20a302Sas200622 870dc20a302Sas200622 /* similar sum to determine how much local memory is required */ 871dc20a302Sas200622 n_alloc = n_fixed + n_variable; 872dc20a302Sas200622 8738d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 874dc20a302Sas200622 if (!rc) 875dc20a302Sas200622 return (rc); /* error already set */ 876dc20a302Sas200622 8778d7e4166Sjose borrego switch (nds->m_op) { 878dc20a302Sas200622 case NDR_M_OP_MARSHALL: 879dc20a302Sas200622 size_is = outer_ref->size_is; 8808d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 881dc20a302Sas200622 if (!rc) 882dc20a302Sas200622 return (0); /* error already set */ 883dc20a302Sas200622 884dc20a302Sas200622 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) 890dc20a302Sas200622 assert(valp == *outer_ref->backptr); 891f96bd5c8SAlan Wright n_ptr_offset = 4; 892dc20a302Sas200622 break; 893dc20a302Sas200622 894dc20a302Sas200622 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 */ 9008d7e4166Sjose borrego rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 901dc20a302Sas200622 if (!rc) 902dc20a302Sas200622 return (0); /* error already set */ 903dc20a302Sas200622 904dc20a302Sas200622 if (size_is != outer_ref->size_is) { 905dc20a302Sas200622 NDR_SET_ERROR(outer_ref, 906dc20a302Sas200622 NDR_ERR_SIZE_IS_MISMATCH_PDU); 907dc20a302Sas200622 return (0); 908dc20a302Sas200622 } 909dc20a302Sas200622 910f96bd5c8SAlan Wright n_ptr_offset = 4; 911f96bd5c8SAlan Wright } 912f96bd5c8SAlan Wright 9133ad684d6Sjb150015 if (size_is > 0) { 9148d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 915dc20a302Sas200622 if (!valp) { 916dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 917dc20a302Sas200622 return (0); 918dc20a302Sas200622 } 9193ad684d6Sjb150015 } 9203ad684d6Sjb150015 921dc20a302Sas200622 if (outer_ref->backptr) 922dc20a302Sas200622 *outer_ref->backptr = valp; 923dc20a302Sas200622 outer_ref->datum = valp; 924dc20a302Sas200622 break; 925dc20a302Sas200622 926dc20a302Sas200622 default: 927dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 928dc20a302Sas200622 return (0); 929dc20a302Sas200622 } 930dc20a302Sas200622 9313ad684d6Sjb150015 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 9323ad684d6Sjb150015 outer_ref->type_flags = NDR_F_NONE; 9333ad684d6Sjb150015 outer_ref->inner_flags = NDR_F_NONE; 9343ad684d6Sjb150015 9353ad684d6Sjb150015 if (size_is > 0) { 936dc20a302Sas200622 bzero(&myref, sizeof (myref)); 9378d7e4166Sjose borrego myref.stream = nds; 938dc20a302Sas200622 myref.enclosing = outer_ref; 939dc20a302Sas200622 myref.ti = outer_ref->ti; 940dc20a302Sas200622 myref.datum = outer_ref->datum; 941dc20a302Sas200622 myref.name = "CONFORMANT-ARRAY"; 942dc20a302Sas200622 myref.outer_flags = NDR_F_NONE; 943dc20a302Sas200622 myref.inner_flags = NDR_F_SIZE_IS; 944dc20a302Sas200622 myref.size_is = outer_ref->size_is; 945dc20a302Sas200622 946dc20a302Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 947dc20a302Sas200622 myref.dimension_is = outer_ref->size_is; /* convenient */ 948dc20a302Sas200622 949f96bd5c8SAlan Wright myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset; 950dc20a302Sas200622 9518d7e4166Sjose borrego rc = ndr_inner(&myref); 952dc20a302Sas200622 if (!rc) 953dc20a302Sas200622 return (rc); /* error already set */ 9543ad684d6Sjb150015 } 955dc20a302Sas200622 9568d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 957dc20a302Sas200622 return (1); 958dc20a302Sas200622 } 959dc20a302Sas200622 960dc20a302Sas200622 int 9618d7e4166Sjose borrego ndr_outer_conformant_construct(ndr_ref_t *outer_ref) 962dc20a302Sas200622 { 9638d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 9648d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 9658d7e4166Sjose borrego ndr_ref_t myref; 966dc20a302Sas200622 char *valp = NULL; 967dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 968dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 969dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 970dc20a302Sas200622 unsigned long size_is; 971dc20a302Sas200622 int rc; 972dc20a302Sas200622 unsigned n_hdr; 973dc20a302Sas200622 unsigned n_fixed; 974dc20a302Sas200622 unsigned n_variable; 975dc20a302Sas200622 unsigned n_alloc; 976dc20a302Sas200622 unsigned n_pdu_total; 977dc20a302Sas200622 int params; 978dc20a302Sas200622 979dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 980dc20a302Sas200622 981dc20a302Sas200622 assert(is_varlen && !is_string && !is_union); 982dc20a302Sas200622 assert(params == NDR_F_NONE); 983dc20a302Sas200622 984dc20a302Sas200622 /* conformant header for this */ 985dc20a302Sas200622 n_hdr = 4; 986dc20a302Sas200622 987dc20a302Sas200622 /* fixed part -- exactly one of these */ 988dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part; 989dc20a302Sas200622 990dc20a302Sas200622 /* variable part -- exactly size_of of these */ 991dc20a302Sas200622 n_variable = 0; /* 0 for the moment */ 992dc20a302Sas200622 993dc20a302Sas200622 /* sum them up to determine the PDU space required */ 994dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 995dc20a302Sas200622 996dc20a302Sas200622 /* similar sum to determine how much local memory is required */ 997dc20a302Sas200622 n_alloc = n_fixed + n_variable; 998dc20a302Sas200622 999dc20a302Sas200622 /* For the moment, grow enough for the fixed-size part */ 10008d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1001dc20a302Sas200622 if (!rc) 1002dc20a302Sas200622 return (rc); /* error already set */ 1003dc20a302Sas200622 10048d7e4166Sjose borrego switch (nds->m_op) { 1005dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1006dc20a302Sas200622 /* 1007dc20a302Sas200622 * We don't know the size yet. We have to wait for 1008dc20a302Sas200622 * it. Proceed with the fixed-size part, and await 10098d7e4166Sjose borrego * the call to ndr_size_is(). 1010dc20a302Sas200622 */ 1011dc20a302Sas200622 size_is = 0; 10128d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1013dc20a302Sas200622 if (!rc) 1014dc20a302Sas200622 return (0); /* error already set */ 1015dc20a302Sas200622 1016dc20a302Sas200622 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) 1022dc20a302Sas200622 assert(valp == *outer_ref->backptr); 1023dc20a302Sas200622 break; 1024dc20a302Sas200622 1025dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1026dc20a302Sas200622 /* 1027dc20a302Sas200622 * We know the size of the variable part because 1028dc20a302Sas200622 * of the CONFORMANT header. We will verify 1029dc20a302Sas200622 * the header against the [size_is(X)] advice 10308d7e4166Sjose borrego * later when ndr_size_is() is called. 1031dc20a302Sas200622 */ 10328d7e4166Sjose borrego rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is); 1033dc20a302Sas200622 if (!rc) 1034dc20a302Sas200622 return (0); /* error already set */ 1035dc20a302Sas200622 1036dc20a302Sas200622 /* recalculate metrics */ 1037dc20a302Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 1038dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1039dc20a302Sas200622 n_alloc = n_fixed + n_variable; 1040dc20a302Sas200622 10418d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1042dc20a302Sas200622 if (!rc) 1043dc20a302Sas200622 return (rc); /* error already set */ 1044dc20a302Sas200622 1045dc20a302Sas200622 outer_ref->size_is = size_is; /* verified later */ 1046dc20a302Sas200622 10478d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1048dc20a302Sas200622 if (!valp) { 1049dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1050dc20a302Sas200622 return (0); 1051dc20a302Sas200622 } 1052dc20a302Sas200622 if (outer_ref->backptr) 1053dc20a302Sas200622 *outer_ref->backptr = valp; 1054dc20a302Sas200622 outer_ref->datum = valp; 1055dc20a302Sas200622 break; 1056dc20a302Sas200622 1057dc20a302Sas200622 default: 1058dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1059dc20a302Sas200622 return (0); 1060dc20a302Sas200622 } 1061dc20a302Sas200622 10623ad684d6Sjb150015 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 10633ad684d6Sjb150015 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 10643ad684d6Sjb150015 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 10653ad684d6Sjb150015 1066dc20a302Sas200622 bzero(&myref, sizeof (myref)); 10678d7e4166Sjose borrego myref.stream = nds; 1068dc20a302Sas200622 myref.enclosing = outer_ref; 1069dc20a302Sas200622 myref.ti = outer_ref->ti; 1070dc20a302Sas200622 myref.datum = outer_ref->datum; 1071dc20a302Sas200622 myref.name = "CONFORMANT-CONSTRUCT"; 1072dc20a302Sas200622 myref.outer_flags = NDR_F_NONE; 1073dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 1074dc20a302Sas200622 myref.size_is = outer_ref->size_is; 1075dc20a302Sas200622 1076dc20a302Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4; 1077dc20a302Sas200622 10788d7e4166Sjose borrego rc = ndr_inner(&myref); 1079dc20a302Sas200622 if (!rc) 1080dc20a302Sas200622 return (rc); /* error already set */ 1081dc20a302Sas200622 10828d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1083dc20a302Sas200622 1084dc20a302Sas200622 if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 1085dc20a302Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 1086dc20a302Sas200622 return (0); 1087dc20a302Sas200622 } 1088dc20a302Sas200622 1089dc20a302Sas200622 return (1); 1090dc20a302Sas200622 } 1091dc20a302Sas200622 1092dc20a302Sas200622 int 10938d7e4166Sjose borrego ndr_size_is(ndr_ref_t *ref) 1094dc20a302Sas200622 { 10958d7e4166Sjose borrego ndr_stream_t *nds = ref->stream; 10968d7e4166Sjose borrego ndr_ref_t *outer_ref = nds->outer_current; 10978d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 1098dc20a302Sas200622 unsigned long size_is; 1099dc20a302Sas200622 int rc; 1100dc20a302Sas200622 unsigned n_hdr; 1101dc20a302Sas200622 unsigned n_fixed; 1102dc20a302Sas200622 unsigned n_variable; 1103dc20a302Sas200622 unsigned n_pdu_total; 1104dc20a302Sas200622 1105dc20a302Sas200622 assert(ref->inner_flags & NDR_F_SIZE_IS); 1106dc20a302Sas200622 size_is = ref->size_is; 1107dc20a302Sas200622 1108dc20a302Sas200622 if (outer_ref->type_flags != NDR_F_SIZE_IS) { 1109dc20a302Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 1110dc20a302Sas200622 return (0); 1111dc20a302Sas200622 } 1112dc20a302Sas200622 1113dc20a302Sas200622 if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 1114dc20a302Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 1115dc20a302Sas200622 return (0); 1116dc20a302Sas200622 } 1117dc20a302Sas200622 11188d7e4166Sjose borrego /* repeat metrics, see ndr_conformant_construct() above */ 1119dc20a302Sas200622 n_hdr = 4; 1120dc20a302Sas200622 n_fixed = ti->pdu_size_fixed_part; 1121dc20a302Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 1122dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1123dc20a302Sas200622 11248d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1125dc20a302Sas200622 if (!rc) 1126dc20a302Sas200622 return (rc); /* error already set */ 1127dc20a302Sas200622 11288d7e4166Sjose borrego switch (nds->m_op) { 1129dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1130dc20a302Sas200622 /* 1131dc20a302Sas200622 * We have to set the sizing header and extend 1132dc20a302Sas200622 * the size of the PDU (already done). 1133dc20a302Sas200622 */ 11348d7e4166Sjose borrego rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is); 1135dc20a302Sas200622 if (!rc) 1136dc20a302Sas200622 return (0); /* error already set */ 1137dc20a302Sas200622 break; 1138dc20a302Sas200622 1139dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1140dc20a302Sas200622 /* 11418d7e4166Sjose borrego * Allocation done during ndr_conformant_construct(). 1142dc20a302Sas200622 * All we are doing here is verifying that the 1143dc20a302Sas200622 * intended size (ref->size_is) matches the sizing header. 1144dc20a302Sas200622 */ 1145dc20a302Sas200622 if (size_is != outer_ref->size_is) { 1146dc20a302Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 1147dc20a302Sas200622 return (0); 1148dc20a302Sas200622 } 1149dc20a302Sas200622 break; 1150dc20a302Sas200622 1151dc20a302Sas200622 default: 1152dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1153dc20a302Sas200622 return (0); 1154dc20a302Sas200622 } 1155dc20a302Sas200622 1156dc20a302Sas200622 outer_ref->inner_flags |= NDR_F_SIZE_IS; 1157dc20a302Sas200622 outer_ref->size_is = ref->size_is; 1158dc20a302Sas200622 return (1); 1159dc20a302Sas200622 } 1160dc20a302Sas200622 1161dc20a302Sas200622 int 11628d7e4166Sjose borrego ndr_outer_string(ndr_ref_t *outer_ref) 1163dc20a302Sas200622 { 11648d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 11658d7e4166Sjose borrego ndr_typeinfo_t *ti = outer_ref->ti; 11668d7e4166Sjose borrego ndr_ref_t myref; 1167dc20a302Sas200622 char *valp = NULL; 1168dc20a302Sas200622 unsigned is_varlen = ti->pdu_size_variable_part; 1169dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 1170dc20a302Sas200622 int is_string = NDR_IS_STRING(ti); 1171dc20a302Sas200622 int rc; 1172dc20a302Sas200622 unsigned n_zeroes; 1173dc20a302Sas200622 unsigned ix; 1174dc20a302Sas200622 unsigned long size_is; 1175dc20a302Sas200622 unsigned long first_is; 1176dc20a302Sas200622 unsigned long length_is; 1177dc20a302Sas200622 unsigned n_hdr; 1178dc20a302Sas200622 unsigned n_fixed; 1179dc20a302Sas200622 unsigned n_variable; 1180dc20a302Sas200622 unsigned n_alloc; 1181dc20a302Sas200622 unsigned n_pdu_total; 1182dc20a302Sas200622 int params; 1183dc20a302Sas200622 1184dc20a302Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 1185dc20a302Sas200622 1186dc20a302Sas200622 assert(is_varlen && is_string && !is_union); 1187dc20a302Sas200622 assert(params == NDR_F_NONE); 1188dc20a302Sas200622 1189dc20a302Sas200622 /* string header for this: size_is first_is length_is */ 1190dc20a302Sas200622 n_hdr = 12; 1191dc20a302Sas200622 1192dc20a302Sas200622 /* fixed part -- exactly none of these */ 1193dc20a302Sas200622 n_fixed = 0; 1194dc20a302Sas200622 11958d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_hdr)) 1196dc20a302Sas200622 return (0); /* error already set */ 1197dc20a302Sas200622 11988d7e4166Sjose borrego switch (nds->m_op) { 1199dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1200dc20a302Sas200622 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 } 1205dc20a302Sas200622 1206dc20a302Sas200622 if (outer_ref->backptr) 1207dc20a302Sas200622 assert(valp == *outer_ref->backptr); 1208dc20a302Sas200622 1209dc20a302Sas200622 if (ti == &ndt_s_wchar) { 1210dc20a302Sas200622 /* 1211a0aa776eSAlan Wright * size_is is the number of characters in the 1212a0aa776eSAlan Wright * (multibyte) string, including the null. 1213dc20a302Sas200622 */ 1214fe1c642dSBill Krier size_is = smb_wcequiv_strlen(valp) / 1215fe1c642dSBill Krier sizeof (smb_wchar_t); 1216fe1c642dSBill Krier 1217fe1c642dSBill Krier if (!(nds->flags & NDS_F_NONULL)) 1218fe1c642dSBill Krier ++size_is; 1219dc20a302Sas200622 1220dc20a302Sas200622 if (size_is > NDR_STRING_MAX) { 1221dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1222dc20a302Sas200622 return (0); 1223dc20a302Sas200622 } 1224dc20a302Sas200622 } else { 1225dc20a302Sas200622 valp = outer_ref->datum; 1226dc20a302Sas200622 n_zeroes = 0; 1227f96bd5c8SAlan Wright for (ix = 0; ix < NDR_STRING_MAX; ix++) { 1228dc20a302Sas200622 if (valp[ix] == 0) { 1229dc20a302Sas200622 n_zeroes++; 1230dc20a302Sas200622 if (n_zeroes >= is_varlen && 1231dc20a302Sas200622 ix % is_varlen == 0) { 1232dc20a302Sas200622 break; 1233dc20a302Sas200622 } 1234dc20a302Sas200622 } else { 1235dc20a302Sas200622 n_zeroes = 0; 1236dc20a302Sas200622 } 1237dc20a302Sas200622 } 1238f96bd5c8SAlan Wright if (ix >= NDR_STRING_MAX) { 1239dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1240dc20a302Sas200622 return (0); 1241dc20a302Sas200622 } 1242dc20a302Sas200622 size_is = ix+1; 1243dc20a302Sas200622 } 1244dc20a302Sas200622 1245dc20a302Sas200622 first_is = 0; 1246dc20a302Sas200622 12478d7e4166Sjose borrego if (nds->flags & NDS_F_NOTERM) 1248dc20a302Sas200622 length_is = size_is - 1; 1249dc20a302Sas200622 else 1250dc20a302Sas200622 length_is = size_is; 1251dc20a302Sas200622 12528d7e4166Sjose borrego if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) || 12538d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 4, &first_is) || 12548d7e4166Sjose borrego !ndr_outer_poke_sizing(outer_ref, 8, &length_is)) 1255dc20a302Sas200622 return (0); /* error already set */ 1256dc20a302Sas200622 break; 1257dc20a302Sas200622 1258dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 12598d7e4166Sjose borrego if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) || 12608d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 4, &first_is) || 12618d7e4166Sjose borrego !ndr_outer_peek_sizing(outer_ref, 8, &length_is)) 1262dc20a302Sas200622 return (0); /* error already set */ 1263dc20a302Sas200622 1264dc20a302Sas200622 /* 1265dc20a302Sas200622 * In addition to the first_is check, we used to check that 1266dc20a302Sas200622 * size_is or size_is-1 was equal to length_is but Windows95 1267dc20a302Sas200622 * doesn't conform to this "rule" (see variable part below). 1268dc20a302Sas200622 * The srvmgr tool for Windows95 sent the following values 1269dc20a302Sas200622 * for a path string: 1270dc20a302Sas200622 * 1271dc20a302Sas200622 * size_is = 261 (0x105) 1272dc20a302Sas200622 * first_is = 0 1273dc20a302Sas200622 * length_is = 53 (0x35) 1274dc20a302Sas200622 * 1275dc20a302Sas200622 * The length_is was correct (for the given path) but the 1276dc20a302Sas200622 * size_is was the maximum path length rather than being 1277dc20a302Sas200622 * related to length_is. 1278dc20a302Sas200622 */ 1279dc20a302Sas200622 if (first_is != 0) { 1280dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1281dc20a302Sas200622 return (0); 1282dc20a302Sas200622 } 1283dc20a302Sas200622 1284dc20a302Sas200622 if (ti == &ndt_s_wchar) { 1285dc20a302Sas200622 /* 1286dc20a302Sas200622 * Decoding Unicode to UTF-8; we need to allow 1287dc20a302Sas200622 * for the maximum possible char size. It would 1288dc20a302Sas200622 * be nice to use mbequiv_strlen but the string 1289dc20a302Sas200622 * may not be null terminated. 1290dc20a302Sas200622 */ 1291dc20a302Sas200622 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX; 1292dc20a302Sas200622 } else { 1293dc20a302Sas200622 n_alloc = (size_is + 1) * is_varlen; 1294dc20a302Sas200622 } 1295dc20a302Sas200622 12968d7e4166Sjose borrego valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1297dc20a302Sas200622 if (!valp) { 1298dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1299dc20a302Sas200622 return (0); 1300dc20a302Sas200622 } 1301dc20a302Sas200622 1302dc20a302Sas200622 bzero(valp, (size_is+1) * is_varlen); 1303dc20a302Sas200622 1304dc20a302Sas200622 if (outer_ref->backptr) 1305dc20a302Sas200622 *outer_ref->backptr = valp; 1306dc20a302Sas200622 outer_ref->datum = valp; 1307dc20a302Sas200622 break; 1308dc20a302Sas200622 1309dc20a302Sas200622 default: 1310dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1311dc20a302Sas200622 return (0); 1312dc20a302Sas200622 } 1313dc20a302Sas200622 1314dc20a302Sas200622 /* 1315dc20a302Sas200622 * Variable part - exactly length_is of these. 1316dc20a302Sas200622 * 1317dc20a302Sas200622 * Usually, length_is is same as size_is and includes nul. 1318dc20a302Sas200622 * Some protocols use length_is = size_is-1, and length_is does 1319dc20a302Sas200622 * not include the nul (which is more consistent with DCE spec). 1320dc20a302Sas200622 * If the length_is is 0, there is no data following the 1321dc20a302Sas200622 * sizing header, regardless of size_is. 1322dc20a302Sas200622 */ 1323dc20a302Sas200622 n_variable = length_is * is_varlen; 1324dc20a302Sas200622 1325dc20a302Sas200622 /* sum them up to determine the PDU space required */ 1326dc20a302Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1327dc20a302Sas200622 1328dc20a302Sas200622 /* similar sum to determine how much local memory is required */ 1329dc20a302Sas200622 n_alloc = n_fixed + n_variable; 1330dc20a302Sas200622 13318d7e4166Sjose borrego rc = ndr_outer_grow(outer_ref, n_pdu_total); 1332dc20a302Sas200622 if (!rc) 1333dc20a302Sas200622 return (rc); /* error already set */ 1334dc20a302Sas200622 1335dc20a302Sas200622 if (length_is > 0) { 1336dc20a302Sas200622 bzero(&myref, sizeof (myref)); 13378d7e4166Sjose borrego myref.stream = nds; 1338dc20a302Sas200622 myref.enclosing = outer_ref; 1339dc20a302Sas200622 myref.ti = outer_ref->ti; 1340dc20a302Sas200622 myref.datum = outer_ref->datum; 1341dc20a302Sas200622 myref.name = "OUTER-STRING"; 1342dc20a302Sas200622 myref.outer_flags = NDR_F_IS_STRING; 1343dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 1344dc20a302Sas200622 1345dc20a302Sas200622 /* 13468d7e4166Sjose borrego * Set up size_is and strlen_is for ndr_s_wchar. 1347dc20a302Sas200622 */ 1348dc20a302Sas200622 myref.size_is = size_is; 1349dc20a302Sas200622 myref.strlen_is = length_is; 1350dc20a302Sas200622 } 1351dc20a302Sas200622 1352dc20a302Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 12; 1353dc20a302Sas200622 1354dc20a302Sas200622 /* 1355dc20a302Sas200622 * Don't try to decode empty strings. 1356dc20a302Sas200622 */ 1357dc20a302Sas200622 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 13588d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1359dc20a302Sas200622 return (1); 1360dc20a302Sas200622 } 1361dc20a302Sas200622 1362dc20a302Sas200622 if ((size_is != 0) && (length_is != 0)) { 13638d7e4166Sjose borrego rc = ndr_inner(&myref); 1364dc20a302Sas200622 if (!rc) 1365dc20a302Sas200622 return (rc); /* error already set */ 1366dc20a302Sas200622 } 1367dc20a302Sas200622 13688d7e4166Sjose borrego nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1369dc20a302Sas200622 return (1); 1370dc20a302Sas200622 } 1371dc20a302Sas200622 1372dc20a302Sas200622 int 13738d7e4166Sjose borrego ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset, 1374dc20a302Sas200622 unsigned long *sizing_p) 1375dc20a302Sas200622 { 13768d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 1377dc20a302Sas200622 unsigned long pdu_offset; 1378dc20a302Sas200622 int rc; 1379dc20a302Sas200622 1380dc20a302Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 1381dc20a302Sas200622 13828d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 13838d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 13848d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1385dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1386dc20a302Sas200622 return (0); 1387dc20a302Sas200622 } 1388dc20a302Sas200622 13898d7e4166Sjose borrego switch (nds->m_op) { 1390dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1391dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1392dc20a302Sas200622 return (0); 1393dc20a302Sas200622 1394dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 13958d7e4166Sjose borrego rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p, 13968d7e4166Sjose borrego nds->swap, outer_ref); 1397dc20a302Sas200622 break; 1398dc20a302Sas200622 1399dc20a302Sas200622 default: 1400dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1401dc20a302Sas200622 return (0); 1402dc20a302Sas200622 } 1403dc20a302Sas200622 1404dc20a302Sas200622 return (rc); 1405dc20a302Sas200622 } 1406dc20a302Sas200622 1407dc20a302Sas200622 int 14088d7e4166Sjose borrego ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset, 1409dc20a302Sas200622 unsigned long *sizing_p) 1410dc20a302Sas200622 { 14118d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 1412dc20a302Sas200622 unsigned long pdu_offset; 1413dc20a302Sas200622 int rc; 1414dc20a302Sas200622 1415dc20a302Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 1416dc20a302Sas200622 14178d7e4166Sjose borrego if (pdu_offset < nds->outer_current->pdu_offset || 14188d7e4166Sjose borrego pdu_offset > nds->outer_current->pdu_end_offset || 14198d7e4166Sjose borrego pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1420dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1421dc20a302Sas200622 return (0); 1422dc20a302Sas200622 } 1423dc20a302Sas200622 14248d7e4166Sjose borrego switch (nds->m_op) { 1425dc20a302Sas200622 case NDR_M_OP_MARSHALL: 14268d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p, 14278d7e4166Sjose borrego nds->swap, outer_ref); 1428dc20a302Sas200622 break; 1429dc20a302Sas200622 1430dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1431dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1432dc20a302Sas200622 return (0); 1433dc20a302Sas200622 1434dc20a302Sas200622 default: 1435dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1436dc20a302Sas200622 return (0); 1437dc20a302Sas200622 } 1438dc20a302Sas200622 1439dc20a302Sas200622 return (rc); 1440dc20a302Sas200622 } 1441dc20a302Sas200622 1442dc20a302Sas200622 /* 1443dc20a302Sas200622 * All OUTER constructs begin on a mod4 (dword) boundary - except 1444dc20a302Sas200622 * for the ones that don't: some MSRPC calls appear to use word or 1445dc20a302Sas200622 * packed alignment. Strings appear to be dword aligned. 1446dc20a302Sas200622 */ 1447dc20a302Sas200622 int 14488d7e4166Sjose borrego ndr_outer_align(ndr_ref_t *outer_ref) 1449dc20a302Sas200622 { 14508d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 1451dc20a302Sas200622 int rc; 1452dc20a302Sas200622 unsigned n_pad; 1453dc20a302Sas200622 unsigned align; 1454dc20a302Sas200622 1455dc20a302Sas200622 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 1456dc20a302Sas200622 align = outer_ref->ti->alignment; 14578d7e4166Sjose borrego n_pad = ((align + 1) - nds->pdu_scan_offset) & align; 1458dc20a302Sas200622 } else { 14598d7e4166Sjose borrego n_pad = NDR_ALIGN4(nds->pdu_scan_offset); 1460dc20a302Sas200622 } 1461dc20a302Sas200622 1462dc20a302Sas200622 if (n_pad == 0) 1463dc20a302Sas200622 return (1); /* already aligned, often the case */ 1464dc20a302Sas200622 14658d7e4166Sjose borrego if (!ndr_outer_grow(outer_ref, n_pad)) 1466dc20a302Sas200622 return (0); /* error already set */ 1467dc20a302Sas200622 14688d7e4166Sjose borrego switch (nds->m_op) { 1469dc20a302Sas200622 case NDR_M_OP_MARSHALL: 14708d7e4166Sjose borrego rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref); 1471dc20a302Sas200622 if (!rc) { 1472dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 1473dc20a302Sas200622 return (0); 1474dc20a302Sas200622 } 1475dc20a302Sas200622 break; 1476dc20a302Sas200622 1477dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1478dc20a302Sas200622 break; 1479dc20a302Sas200622 1480dc20a302Sas200622 default: 1481dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1482dc20a302Sas200622 return (0); 1483dc20a302Sas200622 } 1484dc20a302Sas200622 14858d7e4166Sjose borrego nds->pdu_scan_offset += n_pad; 1486dc20a302Sas200622 return (1); 1487dc20a302Sas200622 } 1488dc20a302Sas200622 1489dc20a302Sas200622 int 14908d7e4166Sjose borrego ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total) 1491dc20a302Sas200622 { 14928d7e4166Sjose borrego ndr_stream_t *nds = outer_ref->stream; 1493dc20a302Sas200622 unsigned long pdu_want_size; 1494dc20a302Sas200622 int rc, is_ok = 0; 1495dc20a302Sas200622 14968d7e4166Sjose borrego pdu_want_size = nds->pdu_scan_offset + n_total; 1497dc20a302Sas200622 14988d7e4166Sjose borrego if (pdu_want_size <= nds->pdu_max_size) { 1499dc20a302Sas200622 is_ok = 1; 1500dc20a302Sas200622 } 1501dc20a302Sas200622 15028d7e4166Sjose borrego switch (nds->m_op) { 1503dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1504dc20a302Sas200622 if (is_ok) 1505dc20a302Sas200622 break; 15068d7e4166Sjose borrego rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref); 1507dc20a302Sas200622 if (!rc) { 1508dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 1509dc20a302Sas200622 return (0); 1510dc20a302Sas200622 } 1511dc20a302Sas200622 break; 1512dc20a302Sas200622 1513dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1514dc20a302Sas200622 if (is_ok) 1515dc20a302Sas200622 break; 1516dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 1517dc20a302Sas200622 return (0); 1518dc20a302Sas200622 1519dc20a302Sas200622 default: 1520dc20a302Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1521dc20a302Sas200622 return (0); 1522dc20a302Sas200622 } 1523dc20a302Sas200622 15248d7e4166Sjose borrego if (nds->pdu_size < pdu_want_size) 15258d7e4166Sjose borrego nds->pdu_size = pdu_want_size; 1526dc20a302Sas200622 1527dc20a302Sas200622 outer_ref->pdu_end_offset = pdu_want_size; 1528dc20a302Sas200622 return (1); 1529dc20a302Sas200622 } 1530dc20a302Sas200622 1531dc20a302Sas200622 /* 1532dc20a302Sas200622 * INNER ELEMENTS 1533dc20a302Sas200622 * 1534dc20a302Sas200622 * The local datum (arg_ref->datum) already exists, there is no need to 1535dc20a302Sas200622 * malloc() it. The datum should point at a member of a structure. 1536dc20a302Sas200622 * 15378d7e4166Sjose borrego * For the most part, ndr_inner() and its helpers are just a sanity 1538dc20a302Sas200622 * check. The underlying ti->ndr_func() could be called immediately 1539dc20a302Sas200622 * for non-pointer elements. For the sake of robustness, we detect 1540dc20a302Sas200622 * run-time errors here. Most of the situations this protects against 1541dc20a302Sas200622 * have already been checked by the IDL compiler. This is also a 1542dc20a302Sas200622 * common point for processing of all data, and so is a convenient 1543dc20a302Sas200622 * place to work from for debugging. 1544dc20a302Sas200622 */ 1545dc20a302Sas200622 int 15468d7e4166Sjose borrego ndr_inner(ndr_ref_t *arg_ref) 1547dc20a302Sas200622 { 15488d7e4166Sjose borrego ndr_typeinfo_t *ti = arg_ref->ti; 1549dc20a302Sas200622 int is_varlen = ti->pdu_size_variable_part; 1550dc20a302Sas200622 int is_union = NDR_IS_UNION(ti); 1551dc20a302Sas200622 int error = NDR_ERR_INNER_PARAMS_BAD; 1552dc20a302Sas200622 int params; 1553dc20a302Sas200622 1554dc20a302Sas200622 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1555dc20a302Sas200622 1556dc20a302Sas200622 switch (params) { 1557dc20a302Sas200622 case NDR_F_NONE: 1558dc20a302Sas200622 if (is_union) { 1559dc20a302Sas200622 error = NDR_ERR_SWITCH_VALUE_MISSING; 1560dc20a302Sas200622 break; 1561dc20a302Sas200622 } 1562dc20a302Sas200622 return (*ti->ndr_func)(arg_ref); 1563dc20a302Sas200622 1564dc20a302Sas200622 case NDR_F_SIZE_IS: 1565dc20a302Sas200622 case NDR_F_DIMENSION_IS: 1566dc20a302Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 1567dc20a302Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 1568dc20a302Sas200622 if (is_varlen) { 1569dc20a302Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 1570dc20a302Sas200622 break; 1571dc20a302Sas200622 } 1572dc20a302Sas200622 if (is_union) { 1573dc20a302Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1574dc20a302Sas200622 break; 1575dc20a302Sas200622 } 1576dc20a302Sas200622 if (params & NDR_F_IS_POINTER) 15778d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1578dc20a302Sas200622 else if (params & NDR_F_IS_REFERENCE) 15798d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1580dc20a302Sas200622 else 15818d7e4166Sjose borrego return (ndr_inner_array(arg_ref)); 1582dc20a302Sas200622 1583dc20a302Sas200622 case NDR_F_IS_POINTER: /* type is pointer to one something */ 1584dc20a302Sas200622 if (is_union) { 1585dc20a302Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1586dc20a302Sas200622 break; 1587dc20a302Sas200622 } 15888d7e4166Sjose borrego return (ndr_inner_pointer(arg_ref)); 1589dc20a302Sas200622 1590dc20a302Sas200622 case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 1591dc20a302Sas200622 if (is_union) { 1592dc20a302Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1593dc20a302Sas200622 break; 1594dc20a302Sas200622 } 15958d7e4166Sjose borrego return (ndr_inner_reference(arg_ref)); 1596dc20a302Sas200622 1597dc20a302Sas200622 case NDR_F_SWITCH_IS: 1598dc20a302Sas200622 if (!is_union) { 1599dc20a302Sas200622 error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 1600dc20a302Sas200622 break; 1601dc20a302Sas200622 } 1602dc20a302Sas200622 return (*ti->ndr_func)(arg_ref); 1603dc20a302Sas200622 1604dc20a302Sas200622 default: 1605dc20a302Sas200622 error = NDR_ERR_INNER_PARAMS_BAD; 1606dc20a302Sas200622 break; 1607dc20a302Sas200622 } 1608dc20a302Sas200622 1609dc20a302Sas200622 /* 1610dc20a302Sas200622 * If we get here, something is wrong. Most likely, 1611dc20a302Sas200622 * the params flags do not match 1612dc20a302Sas200622 */ 1613dc20a302Sas200622 NDR_SET_ERROR(arg_ref, error); 1614dc20a302Sas200622 return (0); 1615dc20a302Sas200622 } 1616dc20a302Sas200622 1617dc20a302Sas200622 int 16188d7e4166Sjose borrego ndr_inner_pointer(ndr_ref_t *arg_ref) 1619dc20a302Sas200622 { 16208d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1621dc20a302Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1622dc20a302Sas200622 char **valpp = (char **)arg_ref->datum; 16238d7e4166Sjose borrego ndr_ref_t *outer_ref; 1624dc20a302Sas200622 16258d7e4166Sjose borrego if (!ndr__ulong(arg_ref)) 1626dc20a302Sas200622 return (0); /* error */ 1627dc20a302Sas200622 if (!*valpp) 1628dc20a302Sas200622 return (1); /* NULL pointer */ 1629dc20a302Sas200622 16308d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1631dc20a302Sas200622 if (!outer_ref) 1632dc20a302Sas200622 return (0); /* error already set */ 1633dc20a302Sas200622 1634f96bd5c8SAlan Wright /* 1635f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1636f96bd5c8SAlan Wright * Retain pointer flag for conformant arrays. 1637f96bd5c8SAlan Wright */ 1638dc20a302Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1639f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1640dc20a302Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 1641f96bd5c8SAlan Wright #ifdef NDR_INNER_PTR_NOT_YET 1642dc20a302Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 1643dc20a302Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1644dc20a302Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1645dc20a302Sas200622 } 1646f96bd5c8SAlan Wright #endif /* NDR_INNER_PTR_NOT_YET */ 1647dc20a302Sas200622 1648dc20a302Sas200622 outer_ref->backptr = valpp; 1649dc20a302Sas200622 16508d7e4166Sjose borrego switch (nds->m_op) { 1651dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1652dc20a302Sas200622 outer_ref->datum = *valpp; 1653dc20a302Sas200622 break; 1654dc20a302Sas200622 1655dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1656dc20a302Sas200622 /* 1657dc20a302Sas200622 * This is probably wrong if the application allocated 1658dc20a302Sas200622 * memory in advance. Indicate no value for now. 1659dc20a302Sas200622 * ONC RPC handles this case. 1660dc20a302Sas200622 */ 1661dc20a302Sas200622 *valpp = 0; 1662dc20a302Sas200622 outer_ref->datum = 0; 1663dc20a302Sas200622 break; 1664dc20a302Sas200622 } 1665dc20a302Sas200622 1666dc20a302Sas200622 return (1); /* pointer dereference scheduled */ 1667dc20a302Sas200622 } 1668dc20a302Sas200622 1669dc20a302Sas200622 int 16708d7e4166Sjose borrego ndr_inner_reference(ndr_ref_t *arg_ref) 1671dc20a302Sas200622 { 16728d7e4166Sjose borrego ndr_stream_t *nds = arg_ref->stream; 1673dc20a302Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1674dc20a302Sas200622 char **valpp = (char **)arg_ref->datum; 16758d7e4166Sjose borrego ndr_ref_t *outer_ref; 1676dc20a302Sas200622 16778d7e4166Sjose borrego outer_ref = ndr_enter_outer_queue(arg_ref); 1678dc20a302Sas200622 if (!outer_ref) 1679dc20a302Sas200622 return (0); /* error already set */ 1680dc20a302Sas200622 1681f96bd5c8SAlan Wright /* 1682f96bd5c8SAlan Wright * Move advice in inner_flags to outer_flags. 1683f96bd5c8SAlan Wright * Retain reference flag for conformant arrays. 1684f96bd5c8SAlan Wright */ 1685dc20a302Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1686f96bd5c8SAlan Wright if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1687dc20a302Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 1688dc20a302Sas200622 #ifdef NDR_INNER_REF_NOT_YET 1689dc20a302Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 1690dc20a302Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1691dc20a302Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1692dc20a302Sas200622 } 1693dc20a302Sas200622 #endif /* NDR_INNER_REF_NOT_YET */ 1694dc20a302Sas200622 1695dc20a302Sas200622 outer_ref->backptr = valpp; 1696dc20a302Sas200622 16978d7e4166Sjose borrego switch (nds->m_op) { 1698dc20a302Sas200622 case NDR_M_OP_MARSHALL: 1699dc20a302Sas200622 outer_ref->datum = *valpp; 1700dc20a302Sas200622 break; 1701dc20a302Sas200622 1702dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 1703dc20a302Sas200622 /* 1704dc20a302Sas200622 * This is probably wrong if the application allocated 1705dc20a302Sas200622 * memory in advance. Indicate no value for now. 1706dc20a302Sas200622 * ONC RPC handles this case. 1707dc20a302Sas200622 */ 1708dc20a302Sas200622 *valpp = 0; 1709dc20a302Sas200622 outer_ref->datum = 0; 1710dc20a302Sas200622 break; 1711dc20a302Sas200622 } 1712dc20a302Sas200622 1713dc20a302Sas200622 return (1); /* pointer dereference scheduled */ 1714dc20a302Sas200622 } 1715dc20a302Sas200622 1716dc20a302Sas200622 int 17178d7e4166Sjose borrego ndr_inner_array(ndr_ref_t *encl_ref) 1718dc20a302Sas200622 { 17198d7e4166Sjose borrego ndr_typeinfo_t *ti = encl_ref->ti; 17208d7e4166Sjose borrego ndr_ref_t myref; 1721dc20a302Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 1722dc20a302Sas200622 unsigned long n_elem; 1723dc20a302Sas200622 unsigned long i; 1724dc20a302Sas200622 char name[30]; 1725dc20a302Sas200622 1726dc20a302Sas200622 if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 1727dc20a302Sas200622 /* now is the time to check/set size */ 17288d7e4166Sjose borrego if (!ndr_size_is(encl_ref)) 1729dc20a302Sas200622 return (0); /* error already set */ 1730dc20a302Sas200622 n_elem = encl_ref->size_is; 1731dc20a302Sas200622 } else { 1732dc20a302Sas200622 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 1733dc20a302Sas200622 n_elem = encl_ref->dimension_is; 1734dc20a302Sas200622 } 1735dc20a302Sas200622 1736dc20a302Sas200622 bzero(&myref, sizeof (myref)); 1737dc20a302Sas200622 myref.enclosing = encl_ref; 1738dc20a302Sas200622 myref.stream = encl_ref->stream; 1739dc20a302Sas200622 myref.packed_alignment = 0; 1740dc20a302Sas200622 myref.ti = ti; 1741dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 1742dc20a302Sas200622 1743dc20a302Sas200622 for (i = 0; i < n_elem; i++) { 1744dc20a302Sas200622 (void) sprintf(name, "[%lu]", i); 1745dc20a302Sas200622 myref.name = name; 1746dc20a302Sas200622 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 1747dc20a302Sas200622 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 1748dc20a302Sas200622 17498d7e4166Sjose borrego if (!ndr_inner(&myref)) 1750dc20a302Sas200622 return (0); 1751dc20a302Sas200622 } 1752dc20a302Sas200622 1753dc20a302Sas200622 return (1); 1754dc20a302Sas200622 } 1755dc20a302Sas200622 1756dc20a302Sas200622 1757dc20a302Sas200622 /* 1758dc20a302Sas200622 * BASIC TYPES 1759dc20a302Sas200622 */ 1760dc20a302Sas200622 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 17618d7e4166Sjose borrego extern int ndr_##TYPE(struct ndr_reference *encl_ref); \ 17628d7e4166Sjose borrego ndr_typeinfo_t ndt_##TYPE = { \ 1763dc20a302Sas200622 1, /* NDR version */ \ 1764dc20a302Sas200622 (SIZE)-1, /* alignment */ \ 1765dc20a302Sas200622 NDR_F_NONE, /* flags */ \ 17668d7e4166Sjose borrego ndr_##TYPE, /* ndr_func */ \ 1767dc20a302Sas200622 SIZE, /* pdu_size_fixed_part */ \ 1768dc20a302Sas200622 0, /* pdu_size_variable_part */ \ 1769dc20a302Sas200622 SIZE, /* c_size_fixed_part */ \ 1770dc20a302Sas200622 0, /* c_size_variable_part */ \ 1771dc20a302Sas200622 }; \ 17728d7e4166Sjose borrego int ndr_##TYPE(struct ndr_reference *ref) { \ 17738d7e4166Sjose borrego return (ndr_basic_integer(ref, SIZE)); \ 1774dc20a302Sas200622 } 1775dc20a302Sas200622 1776dc20a302Sas200622 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 17778d7e4166Sjose borrego extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \ 17788d7e4166Sjose borrego ndr_typeinfo_t ndt_s##TYPE = { \ 1779dc20a302Sas200622 1, /* NDR version */ \ 1780dc20a302Sas200622 (SIZE)-1, /* alignment */ \ 1781dc20a302Sas200622 NDR_F_STRING, /* flags */ \ 17828d7e4166Sjose borrego ndr_s##TYPE, /* ndr_func */ \ 1783dc20a302Sas200622 0, /* pdu_size_fixed_part */ \ 1784dc20a302Sas200622 SIZE, /* pdu_size_variable_part */ \ 1785dc20a302Sas200622 0, /* c_size_fixed_part */ \ 1786dc20a302Sas200622 SIZE, /* c_size_variable_part */ \ 1787dc20a302Sas200622 }; \ 17888d7e4166Sjose borrego int ndr_s##TYPE(struct ndr_reference *ref) { \ 17898d7e4166Sjose borrego return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \ 1790dc20a302Sas200622 } 1791dc20a302Sas200622 1792dc20a302Sas200622 #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 1793dc20a302Sas200622 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1794dc20a302Sas200622 MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 1795dc20a302Sas200622 17968d7e4166Sjose borrego int ndr_basic_integer(ndr_ref_t *, unsigned); 17978d7e4166Sjose borrego int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *); 1798dc20a302Sas200622 1799dc20a302Sas200622 1800dc20a302Sas200622 MAKE_BASIC_TYPE(_char, 1) 1801dc20a302Sas200622 MAKE_BASIC_TYPE(_uchar, 1) 1802dc20a302Sas200622 MAKE_BASIC_TYPE(_short, 2) 1803dc20a302Sas200622 MAKE_BASIC_TYPE(_ushort, 2) 1804dc20a302Sas200622 MAKE_BASIC_TYPE(_long, 4) 1805dc20a302Sas200622 MAKE_BASIC_TYPE(_ulong, 4) 1806dc20a302Sas200622 1807dc20a302Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2) 1808dc20a302Sas200622 1809dc20a302Sas200622 int 18108d7e4166Sjose borrego ndr_basic_integer(ndr_ref_t *ref, unsigned size) 1811dc20a302Sas200622 { 18128d7e4166Sjose borrego ndr_stream_t *nds = ref->stream; 1813dc20a302Sas200622 char *valp = (char *)ref->datum; 1814dc20a302Sas200622 int rc; 1815dc20a302Sas200622 18168d7e4166Sjose borrego switch (nds->m_op) { 1817dc20a302Sas200622 case NDR_M_OP_MARSHALL: 18188d7e4166Sjose borrego rc = NDS_PUT_PDU(nds, ref->pdu_offset, size, 18198d7e4166Sjose borrego valp, nds->swap, ref); 1820dc20a302Sas200622 break; 1821dc20a302Sas200622 1822dc20a302Sas200622 case NDR_M_OP_UNMARSHALL: 18238d7e4166Sjose borrego rc = NDS_GET_PDU(nds, ref->pdu_offset, size, 18248d7e4166Sjose borrego valp, nds->swap, ref); 1825dc20a302Sas200622 break; 1826dc20a302Sas200622 1827dc20a302Sas200622 default: 1828dc20a302Sas200622 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 1829dc20a302Sas200622 return (0); 1830dc20a302Sas200622 } 1831dc20a302Sas200622 1832dc20a302Sas200622 return (rc); 1833dc20a302Sas200622 } 1834dc20a302Sas200622 1835dc20a302Sas200622 int 18368d7e4166Sjose borrego ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under) 1837dc20a302Sas200622 { 1838dc20a302Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 1839dc20a302Sas200622 unsigned size = type_under->pdu_size_fixed_part; 1840dc20a302Sas200622 char *valp; 18418d7e4166Sjose borrego ndr_ref_t myref; 1842dc20a302Sas200622 unsigned long i; 1843dc20a302Sas200622 long sense = 0; 1844dc20a302Sas200622 char name[30]; 1845dc20a302Sas200622 1846dc20a302Sas200622 assert(size != 0); 1847dc20a302Sas200622 1848dc20a302Sas200622 bzero(&myref, sizeof (myref)); 1849dc20a302Sas200622 myref.enclosing = encl_ref; 1850dc20a302Sas200622 myref.stream = encl_ref->stream; 1851dc20a302Sas200622 myref.packed_alignment = 0; 1852dc20a302Sas200622 myref.ti = type_under; 1853dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 1854dc20a302Sas200622 myref.name = name; 1855dc20a302Sas200622 1856dc20a302Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 1857dc20a302Sas200622 (void) sprintf(name, "[%lu]", i); 1858dc20a302Sas200622 myref.pdu_offset = pdu_offset + i * size; 1859dc20a302Sas200622 valp = encl_ref->datum + i * size; 1860dc20a302Sas200622 myref.datum = valp; 1861dc20a302Sas200622 18628d7e4166Sjose borrego if (!ndr_inner(&myref)) 1863dc20a302Sas200622 return (0); 1864dc20a302Sas200622 1865dc20a302Sas200622 switch (size) { 1866dc20a302Sas200622 case 1: sense = *valp; break; 1867dc20a302Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1868dc20a302Sas200622 case 2: sense = *(short *)valp; break; 1869dc20a302Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1870dc20a302Sas200622 case 4: sense = *(long *)valp; break; 1871dc20a302Sas200622 } 1872dc20a302Sas200622 1873dc20a302Sas200622 if (!sense) 1874dc20a302Sas200622 break; 1875dc20a302Sas200622 } 1876dc20a302Sas200622 1877dc20a302Sas200622 return (1); 1878dc20a302Sas200622 } 1879dc20a302Sas200622 1880dc20a302Sas200622 18818d7e4166Sjose borrego extern int ndr_s_wchar(ndr_ref_t *encl_ref); 18828d7e4166Sjose borrego ndr_typeinfo_t ndt_s_wchar = { 1883dc20a302Sas200622 1, /* NDR version */ 1884dc20a302Sas200622 2-1, /* alignment */ 1885dc20a302Sas200622 NDR_F_STRING, /* flags */ 18868d7e4166Sjose borrego ndr_s_wchar, /* ndr_func */ 1887dc20a302Sas200622 0, /* pdu_size_fixed_part */ 1888dc20a302Sas200622 2, /* pdu_size_variable_part */ 1889dc20a302Sas200622 0, /* c_size_fixed_part */ 1890dc20a302Sas200622 1, /* c_size_variable_part */ 1891dc20a302Sas200622 }; 1892dc20a302Sas200622 1893dc20a302Sas200622 1894dc20a302Sas200622 /* 1895dc20a302Sas200622 * Hand coded wchar function because all strings are transported 1896dc20a302Sas200622 * as wide characters. During NDR_M_OP_MARSHALL, we convert from 1897dc20a302Sas200622 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 1898dc20a302Sas200622 * convert from wide characters to multi-byte. 1899dc20a302Sas200622 * 1900dc20a302Sas200622 * It appeared that NT would sometimes leave a spurious character 1901dc20a302Sas200622 * in the data stream before the null wide_char, which would get 1902dc20a302Sas200622 * included in the string decode because we processed until the 1903dc20a302Sas200622 * null character. It now looks like NT does not always terminate 1904dc20a302Sas200622 * RPC Unicode strings and the terminating null is a side effect 1905dc20a302Sas200622 * of field alignment. So now we rely on the strlen_is (set up in 19068d7e4166Sjose borrego * ndr_outer_string) of the enclosing reference. This may or may 1907dc20a302Sas200622 * not include the null but it doesn't matter, the algorithm will 1908dc20a302Sas200622 * get it right. 1909dc20a302Sas200622 */ 1910dc20a302Sas200622 int 19118d7e4166Sjose borrego ndr_s_wchar(ndr_ref_t *encl_ref) 1912dc20a302Sas200622 { 19138d7e4166Sjose borrego ndr_stream_t *nds = encl_ref->stream; 1914dc20a302Sas200622 unsigned short wide_char; 1915dc20a302Sas200622 char *valp; 19168d7e4166Sjose borrego ndr_ref_t myref; 1917dc20a302Sas200622 unsigned long i; 1918dc20a302Sas200622 char name[30]; 1919dc20a302Sas200622 int count; 1920dc20a302Sas200622 int char_count = 0; 1921dc20a302Sas200622 19228d7e4166Sjose borrego if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1923dc20a302Sas200622 /* 1924dc20a302Sas200622 * To avoid problems with zero length strings 1925dc20a302Sas200622 * we can just null terminate here and be done. 1926dc20a302Sas200622 */ 1927dc20a302Sas200622 if (encl_ref->strlen_is == 0) { 1928dc20a302Sas200622 encl_ref->datum[0] = '\0'; 1929dc20a302Sas200622 return (1); 1930dc20a302Sas200622 } 1931dc20a302Sas200622 } 1932dc20a302Sas200622 1933dc20a302Sas200622 bzero(&myref, sizeof (myref)); 1934dc20a302Sas200622 myref.enclosing = encl_ref; 1935dc20a302Sas200622 myref.stream = encl_ref->stream; 1936dc20a302Sas200622 myref.packed_alignment = 0; 1937dc20a302Sas200622 myref.ti = &ndt__wchar; 1938dc20a302Sas200622 myref.inner_flags = NDR_F_NONE; 1939dc20a302Sas200622 myref.datum = (char *)&wide_char; 1940dc20a302Sas200622 myref.name = name; 1941dc20a302Sas200622 myref.pdu_offset = encl_ref->pdu_offset; 1942dc20a302Sas200622 1943dc20a302Sas200622 valp = encl_ref->datum; 1944dc20a302Sas200622 count = 0; 1945dc20a302Sas200622 1946dc20a302Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 1947dc20a302Sas200622 (void) sprintf(name, "[%lu]", i); 1948dc20a302Sas200622 19498d7e4166Sjose borrego if (nds->m_op == NDR_M_OP_MARSHALL) { 1950bbf6f00cSJordan Brown count = smb_mbtowc((smb_wchar_t *)&wide_char, valp, 1951dc20a302Sas200622 MTS_MB_CHAR_MAX); 1952dc20a302Sas200622 if (count < 0) { 1953dc20a302Sas200622 return (0); 1954dc20a302Sas200622 } else if (count == 0) { 1955dc20a302Sas200622 if (encl_ref->strlen_is != encl_ref->size_is) 1956dc20a302Sas200622 break; 1957dc20a302Sas200622 1958dc20a302Sas200622 /* 1959dc20a302Sas200622 * If the input char is 0, mbtowc 1960dc20a302Sas200622 * returns 0 without setting wide_char. 1961dc20a302Sas200622 * Set wide_char to 0 and a count of 1. 1962dc20a302Sas200622 */ 1963dc20a302Sas200622 wide_char = *valp; 1964dc20a302Sas200622 count = 1; 1965dc20a302Sas200622 } 1966dc20a302Sas200622 } 1967dc20a302Sas200622 19688d7e4166Sjose borrego if (!ndr_inner(&myref)) 1969dc20a302Sas200622 return (0); 1970dc20a302Sas200622 19718d7e4166Sjose borrego if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1972bbf6f00cSJordan Brown count = smb_wctomb(valp, wide_char); 1973dc20a302Sas200622 1974dc20a302Sas200622 if ((++char_count) == encl_ref->strlen_is) { 1975dc20a302Sas200622 valp += count; 1976dc20a302Sas200622 *valp = '\0'; 1977dc20a302Sas200622 break; 1978dc20a302Sas200622 } 1979dc20a302Sas200622 } 1980dc20a302Sas200622 1981dc20a302Sas200622 if (!wide_char) 1982dc20a302Sas200622 break; 1983dc20a302Sas200622 1984dc20a302Sas200622 myref.pdu_offset += sizeof (wide_char); 1985dc20a302Sas200622 valp += count; 1986dc20a302Sas200622 } 1987dc20a302Sas200622 1988dc20a302Sas200622 return (1); 1989dc20a302Sas200622 } 1990dc20a302Sas200622 1991dc20a302Sas200622 /* 1992dc20a302Sas200622 * Converts a multibyte character string to a little-endian, wide-char 1993dc20a302Sas200622 * string. No more than nwchars wide characters are stored. 1994dc20a302Sas200622 * A terminating null wide character is appended if there is room. 1995dc20a302Sas200622 * 1996dc20a302Sas200622 * Returns the number of wide characters converted, not counting 1997dc20a302Sas200622 * any terminating null wide character. Returns -1 if an invalid 1998dc20a302Sas200622 * multibyte character is encountered. 1999dc20a302Sas200622 */ 2000dc20a302Sas200622 size_t 2001bbf6f00cSJordan Brown ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs, 2002dc20a302Sas200622 size_t nwchars) 2003dc20a302Sas200622 { 2004bbf6f00cSJordan Brown smb_wchar_t *start = wcs; 2005dc20a302Sas200622 int nbytes; 2006dc20a302Sas200622 2007dc20a302Sas200622 while (nwchars--) { 20088d7e4166Sjose borrego nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX); 2009dc20a302Sas200622 if (nbytes < 0) { 2010dc20a302Sas200622 *wcs = 0; 2011dc20a302Sas200622 return ((size_t)-1); 2012dc20a302Sas200622 } 2013dc20a302Sas200622 2014dc20a302Sas200622 if (*mbs == 0) 2015dc20a302Sas200622 break; 2016dc20a302Sas200622 2017dc20a302Sas200622 ++wcs; 2018dc20a302Sas200622 mbs += nbytes; 2019dc20a302Sas200622 } 2020dc20a302Sas200622 2021dc20a302Sas200622 return (wcs - start); 2022dc20a302Sas200622 } 2023dc20a302Sas200622 2024dc20a302Sas200622 /* 2025dc20a302Sas200622 * Converts a multibyte character to a little-endian, wide-char, which 2026dc20a302Sas200622 * is stored in wcharp. Up to nbytes bytes are examined. 2027dc20a302Sas200622 * 2028dc20a302Sas200622 * If mbchar is valid, returns the number of bytes processed in mbchar. 2029bbf6f00cSJordan Brown * If mbchar is invalid, returns -1. See also smb_mbtowc(). 2030dc20a302Sas200622 */ 2031dc20a302Sas200622 /*ARGSUSED*/ 2032dc20a302Sas200622 int 2033bbf6f00cSJordan Brown ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar, 20348d7e4166Sjose borrego size_t nbytes) 2035dc20a302Sas200622 { 2036dc20a302Sas200622 int rc; 2037dc20a302Sas200622 2038bbf6f00cSJordan Brown if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0) 2039dc20a302Sas200622 return (rc); 2040dc20a302Sas200622 2041dc20a302Sas200622 #ifdef _BIG_ENDIAN 20428d7e4166Sjose borrego if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) 2043dc20a302Sas200622 *wcharp = BSWAP_16(*wcharp); 2044dc20a302Sas200622 #endif 2045dc20a302Sas200622 2046dc20a302Sas200622 return (rc); 2047dc20a302Sas200622 } 2048