1*5772Sas200622 /* 2*5772Sas200622 * CDDL HEADER START 3*5772Sas200622 * 4*5772Sas200622 * The contents of this file are subject to the terms of the 5*5772Sas200622 * Common Development and Distribution License (the "License"). 6*5772Sas200622 * You may not use this file except in compliance with the License. 7*5772Sas200622 * 8*5772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5772Sas200622 * or http://www.opensolaris.org/os/licensing. 10*5772Sas200622 * See the License for the specific language governing permissions 11*5772Sas200622 * and limitations under the License. 12*5772Sas200622 * 13*5772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14*5772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16*5772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17*5772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18*5772Sas200622 * 19*5772Sas200622 * CDDL HEADER END 20*5772Sas200622 */ 21*5772Sas200622 /* 22*5772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*5772Sas200622 * Use is subject to license terms. 24*5772Sas200622 */ 25*5772Sas200622 26*5772Sas200622 #pragma ident "%Z%%M% %I% %E% SMI" 27*5772Sas200622 28*5772Sas200622 /* 29*5772Sas200622 * Network Data Representation (NDR) is a compatible subset of the DCE RPC 30*5772Sas200622 * and MSRPC NDR. NDR is used to move parameters consisting of 31*5772Sas200622 * complicated trees of data constructs between an RPC client and server. 32*5772Sas200622 */ 33*5772Sas200622 34*5772Sas200622 #include <sys/byteorder.h> 35*5772Sas200622 #include <strings.h> 36*5772Sas200622 #include <assert.h> 37*5772Sas200622 #include <string.h> 38*5772Sas200622 #include <stdlib.h> 39*5772Sas200622 40*5772Sas200622 #include <smbsrv/libsmb.h> 41*5772Sas200622 #include <smbsrv/string.h> 42*5772Sas200622 #include <smbsrv/ndr.h> 43*5772Sas200622 44*5772Sas200622 #define NDR_STRING_MAX 256 45*5772Sas200622 46*5772Sas200622 #define NDR_IS_UNION(T) \ 47*5772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION) 48*5772Sas200622 #define NDR_IS_STRING(T) \ 49*5772Sas200622 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING) 50*5772Sas200622 51*5772Sas200622 extern struct ndr_typeinfo ndt_s_wchar; 52*5772Sas200622 53*5772Sas200622 /* 54*5772Sas200622 * The following synopsis describes the terms TOP-MOST, OUTER and INNER. 55*5772Sas200622 * 56*5772Sas200622 * Each parameter (call arguments and return values) is a TOP-MOST item. 57*5772Sas200622 * A TOP-MOST item consists of one or more OUTER items. An OUTER item 58*5772Sas200622 * consists of one or more INNER items. There are important differences 59*5772Sas200622 * between each kind, which, primarily, have to do with the allocation 60*5772Sas200622 * of memory to contain data structures and the order of processing. 61*5772Sas200622 * 62*5772Sas200622 * This is most easily demonstrated with a short example. 63*5772Sas200622 * Consider these structures: 64*5772Sas200622 * 65*5772Sas200622 * struct top_param { 66*5772Sas200622 * long level; 67*5772Sas200622 * struct list * head; 68*5772Sas200622 * long count; 69*5772Sas200622 * }; 70*5772Sas200622 * 71*5772Sas200622 * struct list { 72*5772Sas200622 * struct list * next; 73*5772Sas200622 * char * str; // a string 74*5772Sas200622 * }; 75*5772Sas200622 * 76*5772Sas200622 * Now, consider an instance tree like this: 77*5772Sas200622 * 78*5772Sas200622 * +---------+ +-------+ +-------+ 79*5772Sas200622 * |top_param| +--->|list #1| +--->|list #2| 80*5772Sas200622 * +---------+ | +-------+ | +-------+ 81*5772Sas200622 * | level | | | next ----+ | next --->(NULL) 82*5772Sas200622 * | head ----+ | str -->"foo" | str -->"bar" 83*5772Sas200622 * | count | | flag | | flag | 84*5772Sas200622 * +---------+ +-------+ +-------+ 85*5772Sas200622 * 86*5772Sas200622 * The DCE(MS)/RPC Stub Data encoding for the tree is the following. 87*5772Sas200622 * The vertical bars (|) indicate OUTER construct boundaries. 88*5772Sas200622 * 89*5772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 90*5772Sas200622 * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count| 91*5772Sas200622 * +-----+----------------------+----------------------+-----+-----+-----+ 92*5772Sas200622 * level |<----------------------- head -------------------------->|count 93*5772Sas200622 * TOP TOP TOP 94*5772Sas200622 * 95*5772Sas200622 * Here's what to notice: 96*5772Sas200622 * 97*5772Sas200622 * - The members of the TOP-MOST construct are scattered through the Stub 98*5772Sas200622 * Data in the order they occur. This example shows a TOP-MOST construct 99*5772Sas200622 * consisting of atomic types (pointers and integers). A construct 100*5772Sas200622 * (struct) within the TOP-MOST construct would be contiguous and not 101*5772Sas200622 * scattered. 102*5772Sas200622 * 103*5772Sas200622 * - The members of OUTER constructs are contiguous, which allows for 104*5772Sas200622 * non-copied relocated (fixed-up) data structures at the packet's 105*5772Sas200622 * destination. We don't do fix-ups here. The pointers within the 106*5772Sas200622 * OUTER constructs are processed depth-first in the order that they 107*5772Sas200622 * occur. If they were processed breadth first, the sequence would 108*5772Sas200622 * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may 109*5772Sas200622 * be variable length, and pointers are often encountered before the 110*5772Sas200622 * size(s) is known. 111*5772Sas200622 * 112*5772Sas200622 * - The INNER constructs are simply the members of an OUTER construct. 113*5772Sas200622 * 114*5772Sas200622 * For comparison, consider how ONC RPC would handle the same tree of 115*5772Sas200622 * data. ONC requires very little buffering, while DCE requires enough 116*5772Sas200622 * buffer space for the entire message. ONC does atom-by-atom depth-first 117*5772Sas200622 * (de)serialization and copy, while DCE allows for constructs to be 118*5772Sas200622 * "fixed-up" (relocated) in place at the destination. The packet data 119*5772Sas200622 * for the same tree processed by ONC RPC would look like this: 120*5772Sas200622 * 121*5772Sas200622 * +---------------------------------------------------------------------+ 122*5772Sas200622 * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count| 123*5772Sas200622 * +---------------------------------------------------------------------+ 124*5772Sas200622 * TOP #1 #2 #2 bar #2 #1 foo #1 TOP 125*5772Sas200622 * 126*5772Sas200622 * More details about each TOP-MOST, OUTER, and INNER constructs appear 127*5772Sas200622 * throughout this source file near where such constructs are processed. 128*5772Sas200622 * 129*5772Sas200622 * NDR_REFERENCE 130*5772Sas200622 * 131*5772Sas200622 * The primary object for NDR is the struct ndr_reference. 132*5772Sas200622 * 133*5772Sas200622 * An ndr_reference indicates the local datum (i.e. native "C" data 134*5772Sas200622 * format), and the element within the Stub Data (contained within the 135*5772Sas200622 * RPC PDU (protocol data unit). An ndr_reference also indicates, 136*5772Sas200622 * largely as a debugging aid, something about the type of the 137*5772Sas200622 * element/datum, and the enclosing construct for the element. The 138*5772Sas200622 * ndr_reference's are typically allocated on the stack as locals, 139*5772Sas200622 * and the chain of ndr_reference.enclosing references is in reverse 140*5772Sas200622 * order of the call graph. 141*5772Sas200622 * 142*5772Sas200622 * The ndr_reference.datum is a pointer to the local memory that 143*5772Sas200622 * contains/receives the value. The ndr_reference.pdu_offset indicates 144*5772Sas200622 * where in the Stub Data the value is to be stored/retrieved. 145*5772Sas200622 * 146*5772Sas200622 * The ndr_reference also contains various parameters to the NDR 147*5772Sas200622 * process, such as ndr_reference.size_is, which indicates the size 148*5772Sas200622 * of variable length data, or ndr_reference.switch_is, which 149*5772Sas200622 * indicates the arm of a union to use. 150*5772Sas200622 * 151*5772Sas200622 * QUEUE OF OUTER REFERENCES 152*5772Sas200622 * 153*5772Sas200622 * Some OUTER constructs are variable size. Sometimes (often) we don't 154*5772Sas200622 * know the size of the OUTER construct until after pointers have been 155*5772Sas200622 * encountered. Hence, we can not begin processing the referent of the 156*5772Sas200622 * pointer until after the referring OUTER construct is completely 157*5772Sas200622 * processed, i.e. we don't know where to find/put the referent in the 158*5772Sas200622 * Stub Data until we know the size of all its predecessors. 159*5772Sas200622 * 160*5772Sas200622 * This is managed using the queue of OUTER references. The queue is 161*5772Sas200622 * anchored in mlndr_stream.outer_queue_head. At any time, 162*5772Sas200622 * mlndr_stream.outer_queue_tailp indicates where to put the 163*5772Sas200622 * ndr_reference for the next encountered pointer. 164*5772Sas200622 * 165*5772Sas200622 * Refer to the example above as we illustrate the queue here. In these 166*5772Sas200622 * illustrations, the queue entries are not the data structures themselves. 167*5772Sas200622 * Rather, they are ndr_reference entries which **refer** to the data 168*5772Sas200622 * structures in both the PDU and local memory. 169*5772Sas200622 * 170*5772Sas200622 * During some point in the processing, the queue looks like this: 171*5772Sas200622 * 172*5772Sas200622 * outer_current -------v 173*5772Sas200622 * outer_queue_head --> list#1 --0 174*5772Sas200622 * outer_queue_tailp ---------& 175*5772Sas200622 * 176*5772Sas200622 * When the pointer #1.next is encountered, and entry is added to the 177*5772Sas200622 * queue, 178*5772Sas200622 * 179*5772Sas200622 * outer_current -------v 180*5772Sas200622 * outer_queue_head --> list#1 --> list#2 --0 181*5772Sas200622 * outer_queue_tailp --------------------& 182*5772Sas200622 * 183*5772Sas200622 * and the members of #1 continue to be processed, which encounters 184*5772Sas200622 * #1.str: 185*5772Sas200622 * 186*5772Sas200622 * outer_current -------v 187*5772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 188*5772Sas200622 * outer_queue_tailp ------------------------------& 189*5772Sas200622 * 190*5772Sas200622 * Upon the completion of list#1, the processing continues by moving 191*5772Sas200622 * to mlndr_stream.outer_current->next, and the tail is set to this 192*5772Sas200622 * outer member: 193*5772Sas200622 * 194*5772Sas200622 * outer_current ------------------v 195*5772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "foo" --0 196*5772Sas200622 * outer_queue_tailp --------------------& 197*5772Sas200622 * 198*5772Sas200622 * Space for list#2 is allocated, either in the Stub Data or of local 199*5772Sas200622 * memory. When #2.next is encountered, it is found to be the null 200*5772Sas200622 * pointer and no reference is added to the queue. When #2.str is 201*5772Sas200622 * encountered, it is found to be valid, and a reference is added: 202*5772Sas200622 * 203*5772Sas200622 * outer_current ------------------v 204*5772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 205*5772Sas200622 * outer_queue_tailp ------------------------------& 206*5772Sas200622 * 207*5772Sas200622 * Processing continues in a similar fashion with the string "bar", 208*5772Sas200622 * which is variable-length. At this point, memory for "bar" may be 209*5772Sas200622 * malloc()ed during NDR_M_OP_UNMARSHALL: 210*5772Sas200622 * 211*5772Sas200622 * outer_current -----------------------------v 212*5772Sas200622 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0 213*5772Sas200622 * outer_queue_tailp ------------------------------& 214*5772Sas200622 * 215*5772Sas200622 * And finishes on string "foo". Notice that because "bar" is a 216*5772Sas200622 * variable length string, and we don't know the PDU offset for "foo" 217*5772Sas200622 * until we reach this point. 218*5772Sas200622 * 219*5772Sas200622 * When the queue is drained (current->next==0), processing continues 220*5772Sas200622 * with the next TOP-MOST member. 221*5772Sas200622 * 222*5772Sas200622 * The queue of OUTER constructs manages the variable-length semantics 223*5772Sas200622 * of OUTER constructs and satisfies the depth-first requirement. 224*5772Sas200622 * We allow the queue to linger until the entire TOP-MOST structure is 225*5772Sas200622 * processed as an aid to debugging. 226*5772Sas200622 */ 227*5772Sas200622 228*5772Sas200622 static struct ndr_reference *mlndr_enter_outer_queue(struct ndr_reference *); 229*5772Sas200622 extern int mlndr__ulong(struct ndr_reference *); 230*5772Sas200622 231*5772Sas200622 /* 232*5772Sas200622 * TOP-MOST ELEMENTS 233*5772Sas200622 * 234*5772Sas200622 * This is fundamentally the first OUTER construct of the parameter, 235*5772Sas200622 * possibly followed by more OUTER constructs due to pointers. The 236*5772Sas200622 * datum (local memory) for TOP-MOST constructs (structs) is allocated 237*5772Sas200622 * by the caller of NDR. 238*5772Sas200622 * 239*5772Sas200622 * After the element is transferred, the outer_queue is drained. 240*5772Sas200622 * 241*5772Sas200622 * All we have to do is add an entry to the outer_queue for this 242*5772Sas200622 * top-most member, and commence the outer_queue processing. 243*5772Sas200622 */ 244*5772Sas200622 int 245*5772Sas200622 mlndo_process(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti, 246*5772Sas200622 char *datum) 247*5772Sas200622 { 248*5772Sas200622 struct ndr_reference myref; 249*5772Sas200622 250*5772Sas200622 bzero(&myref, sizeof (myref)); 251*5772Sas200622 myref.stream = mlnds; 252*5772Sas200622 myref.datum = datum; 253*5772Sas200622 myref.name = "PROCESS"; 254*5772Sas200622 myref.ti = ti; 255*5772Sas200622 256*5772Sas200622 return (mlndr_topmost(&myref)); 257*5772Sas200622 } 258*5772Sas200622 259*5772Sas200622 int 260*5772Sas200622 mlndo_operation(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti, 261*5772Sas200622 int opnum, char *datum) 262*5772Sas200622 { 263*5772Sas200622 struct ndr_reference myref; 264*5772Sas200622 265*5772Sas200622 bzero(&myref, sizeof (myref)); 266*5772Sas200622 myref.stream = mlnds; 267*5772Sas200622 myref.datum = datum; 268*5772Sas200622 myref.name = "OPERATION"; 269*5772Sas200622 myref.ti = ti; 270*5772Sas200622 myref.inner_flags = NDR_F_SWITCH_IS; 271*5772Sas200622 myref.switch_is = opnum; 272*5772Sas200622 273*5772Sas200622 if (ti->type_flags != NDR_F_INTERFACE) { 274*5772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE); 275*5772Sas200622 return (0); 276*5772Sas200622 } 277*5772Sas200622 278*5772Sas200622 return ((*ti->ndr_func)(&myref)); 279*5772Sas200622 } 280*5772Sas200622 281*5772Sas200622 int 282*5772Sas200622 mlndr_params(struct ndr_reference *params_ref) 283*5772Sas200622 { 284*5772Sas200622 struct ndr_typeinfo *ti = params_ref->ti; 285*5772Sas200622 286*5772Sas200622 if (ti->type_flags == NDR_F_OPERATION) 287*5772Sas200622 return (*ti->ndr_func) (params_ref); 288*5772Sas200622 else 289*5772Sas200622 return (mlndr_topmost(params_ref)); 290*5772Sas200622 } 291*5772Sas200622 292*5772Sas200622 int 293*5772Sas200622 mlndr_topmost(struct ndr_reference *top_ref) 294*5772Sas200622 { 295*5772Sas200622 struct mlndr_stream *mlnds; 296*5772Sas200622 struct ndr_typeinfo *ti; 297*5772Sas200622 struct ndr_reference *outer_ref = 0; 298*5772Sas200622 int is_varlen; 299*5772Sas200622 int is_string; 300*5772Sas200622 int error; 301*5772Sas200622 int rc; 302*5772Sas200622 unsigned n_fixed; 303*5772Sas200622 int params; 304*5772Sas200622 305*5772Sas200622 assert(top_ref); 306*5772Sas200622 assert(top_ref->stream); 307*5772Sas200622 assert(top_ref->ti); 308*5772Sas200622 309*5772Sas200622 mlnds = top_ref->stream; 310*5772Sas200622 ti = top_ref->ti; 311*5772Sas200622 312*5772Sas200622 is_varlen = ti->pdu_size_variable_part; 313*5772Sas200622 is_string = NDR_IS_STRING(ti); 314*5772Sas200622 315*5772Sas200622 assert(mlnds->outer_queue_tailp && !*mlnds->outer_queue_tailp); 316*5772Sas200622 assert(!mlnds->outer_current); 317*5772Sas200622 318*5772Sas200622 params = top_ref->inner_flags & NDR_F_PARAMS_MASK; 319*5772Sas200622 320*5772Sas200622 switch (params) { 321*5772Sas200622 case NDR_F_NONE: 322*5772Sas200622 case NDR_F_SWITCH_IS: 323*5772Sas200622 if (is_string || is_varlen) { 324*5772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 325*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 326*5772Sas200622 return (0); 327*5772Sas200622 } 328*5772Sas200622 n_fixed = ti->pdu_size_fixed_part; 329*5772Sas200622 break; 330*5772Sas200622 331*5772Sas200622 case NDR_F_SIZE_IS: 332*5772Sas200622 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL; 333*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 334*5772Sas200622 return (0); 335*5772Sas200622 336*5772Sas200622 case NDR_F_DIMENSION_IS: 337*5772Sas200622 if (is_varlen) { 338*5772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 339*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 340*5772Sas200622 return (0); 341*5772Sas200622 } 342*5772Sas200622 n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is; 343*5772Sas200622 break; 344*5772Sas200622 345*5772Sas200622 case NDR_F_IS_POINTER: 346*5772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: 347*5772Sas200622 n_fixed = 4; 348*5772Sas200622 break; 349*5772Sas200622 350*5772Sas200622 case NDR_F_IS_REFERENCE: 351*5772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: 352*5772Sas200622 n_fixed = 0; 353*5772Sas200622 break; 354*5772Sas200622 355*5772Sas200622 default: 356*5772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 357*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 358*5772Sas200622 return (0); 359*5772Sas200622 } 360*5772Sas200622 361*5772Sas200622 outer_ref = mlndr_enter_outer_queue(top_ref); 362*5772Sas200622 if (!outer_ref) 363*5772Sas200622 return (0); /* error already set */ 364*5772Sas200622 365*5772Sas200622 /* 366*5772Sas200622 * Hand-craft the first OUTER construct and directly call 367*5772Sas200622 * mlndr_inner(). Then, run the outer_queue. We do this 368*5772Sas200622 * because mlndr_outer() wants to malloc() memory for 369*5772Sas200622 * the construct, and we already have the memory. 370*5772Sas200622 */ 371*5772Sas200622 372*5772Sas200622 /* move the flags, etc, around again, undoes enter_outer_queue() */ 373*5772Sas200622 outer_ref->inner_flags = top_ref->inner_flags; 374*5772Sas200622 outer_ref->outer_flags = 0; 375*5772Sas200622 outer_ref->datum = top_ref->datum; 376*5772Sas200622 377*5772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 378*5772Sas200622 if (!mlndr_outer_align(outer_ref)) 379*5772Sas200622 return (0); /* error already set */ 380*5772Sas200622 381*5772Sas200622 /* Regardless of what it is, this is where it starts */ 382*5772Sas200622 outer_ref->pdu_offset = mlnds->pdu_scan_offset; 383*5772Sas200622 384*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_fixed); 385*5772Sas200622 if (!rc) 386*5772Sas200622 return (0); /* error already set */ 387*5772Sas200622 388*5772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed; 389*5772Sas200622 390*5772Sas200622 /* set-up outer_current, as though run_outer_queue() was doing it */ 391*5772Sas200622 mlnds->outer_current = outer_ref; 392*5772Sas200622 mlnds->outer_queue_tailp = &mlnds->outer_current->next; 393*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 394*5772Sas200622 395*5772Sas200622 /* do the topmost member */ 396*5772Sas200622 rc = mlndr_inner(outer_ref); 397*5772Sas200622 if (!rc) 398*5772Sas200622 return (0); /* error already set */ 399*5772Sas200622 400*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 401*5772Sas200622 402*5772Sas200622 /* advance, as though run_outer_queue() was doing it */ 403*5772Sas200622 mlnds->outer_current = mlnds->outer_current->next; 404*5772Sas200622 return (mlndr_run_outer_queue(mlnds)); 405*5772Sas200622 } 406*5772Sas200622 407*5772Sas200622 static struct ndr_reference * 408*5772Sas200622 mlndr_enter_outer_queue(struct ndr_reference *arg_ref) 409*5772Sas200622 { 410*5772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 411*5772Sas200622 struct ndr_reference *outer_ref; 412*5772Sas200622 413*5772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 414*5772Sas200622 outer_ref = (struct ndr_reference *) 415*5772Sas200622 MLNDS_MALLOC(mlnds, sizeof (*outer_ref), arg_ref); 416*5772Sas200622 if (!outer_ref) { 417*5772Sas200622 NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED); 418*5772Sas200622 return (0); 419*5772Sas200622 } 420*5772Sas200622 421*5772Sas200622 *outer_ref = *arg_ref; 422*5772Sas200622 423*5772Sas200622 /* move advice in inner_flags to outer_flags */ 424*5772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 425*5772Sas200622 outer_ref->inner_flags = 0; 426*5772Sas200622 outer_ref->enclosing = mlnds->outer_current; 427*5772Sas200622 outer_ref->backptr = 0; 428*5772Sas200622 outer_ref->datum = 0; 429*5772Sas200622 430*5772Sas200622 assert(mlnds->outer_queue_tailp); 431*5772Sas200622 432*5772Sas200622 outer_ref->next = *mlnds->outer_queue_tailp; 433*5772Sas200622 *mlnds->outer_queue_tailp = outer_ref; 434*5772Sas200622 mlnds->outer_queue_tailp = &outer_ref->next; 435*5772Sas200622 return (outer_ref); 436*5772Sas200622 } 437*5772Sas200622 438*5772Sas200622 int 439*5772Sas200622 mlndr_run_outer_queue(struct mlndr_stream *mlnds) 440*5772Sas200622 { 441*5772Sas200622 while (mlnds->outer_current) { 442*5772Sas200622 mlnds->outer_queue_tailp = &mlnds->outer_current->next; 443*5772Sas200622 444*5772Sas200622 if (!mlndr_outer(mlnds->outer_current)) 445*5772Sas200622 return (0); 446*5772Sas200622 447*5772Sas200622 mlnds->outer_current = mlnds->outer_current->next; 448*5772Sas200622 } 449*5772Sas200622 450*5772Sas200622 return (1); 451*5772Sas200622 } 452*5772Sas200622 453*5772Sas200622 /* 454*5772Sas200622 * OUTER CONSTRUCTS 455*5772Sas200622 * 456*5772Sas200622 * OUTER constructs are where the real work is, which stems from the 457*5772Sas200622 * variable-length potential. 458*5772Sas200622 * 459*5772Sas200622 * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT 460*5772Sas200622 * 461*5772Sas200622 * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT, 462*5772Sas200622 * VARYING, and VARYING/CONFORMANT. 463*5772Sas200622 * 464*5772Sas200622 * What makes this so tough is that the variable-length array may be well 465*5772Sas200622 * encapsulated within the outer construct. Further, because DCE(MS)/RPC 466*5772Sas200622 * tries to keep the constructs contiguous in the data stream, the sizing 467*5772Sas200622 * information precedes the entire OUTER construct. The sizing information 468*5772Sas200622 * must be used at the appropriate time, which can be after many, many, 469*5772Sas200622 * many fixed-length elements. During IDL type analysis, we know in 470*5772Sas200622 * advance constructs that encapsulate variable-length constructs. So, 471*5772Sas200622 * we know when we have a sizing header and when we don't. The actual 472*5772Sas200622 * semantics of the header are largely deferred. 473*5772Sas200622 * 474*5772Sas200622 * Currently, VARYING constructs are not implemented but they are described 475*5772Sas200622 * here in case they have to be implemented in the future. Similarly, 476*5772Sas200622 * DCE(MS)/RPC provides for multi-dimensional arrays, which are currently 477*5772Sas200622 * not implemented. Only one-dimensional, variable-length arrays are 478*5772Sas200622 * supported. 479*5772Sas200622 * 480*5772Sas200622 * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW 481*5772Sas200622 * 482*5772Sas200622 * All variable-length values are arrays. These arrays may be embedded 483*5772Sas200622 * well within another construct. However, a variable-length construct 484*5772Sas200622 * may ONLY appear as the last member of an enclosing construct. Example: 485*5772Sas200622 * 486*5772Sas200622 * struct credentials { 487*5772Sas200622 * ulong uid, gid; 488*5772Sas200622 * ulong n_gids; 489*5772Sas200622 * [size_is(n_gids)] 490*5772Sas200622 * ulong gids[*]; // variable-length. 491*5772Sas200622 * }; 492*5772Sas200622 * 493*5772Sas200622 * CONFORMANT constructs have a dynamic size in local memory and in the 494*5772Sas200622 * PDU. The CONFORMANT quality is indicated by the [size_is()] advice. 495*5772Sas200622 * CONFORMANT constructs have the following header: 496*5772Sas200622 * 497*5772Sas200622 * struct conformant_header { 498*5772Sas200622 * ulong size_is; 499*5772Sas200622 * }; 500*5772Sas200622 * 501*5772Sas200622 * (Multi-dimensional CONFORMANT arrays have a similar header for each 502*5772Sas200622 * dimension - not implemented). 503*5772Sas200622 * 504*5772Sas200622 * Example CONFORMANT construct: 505*5772Sas200622 * 506*5772Sas200622 * struct user { 507*5772Sas200622 * char * name; 508*5772Sas200622 * struct credentials cred; // see above 509*5772Sas200622 * }; 510*5772Sas200622 * 511*5772Sas200622 * Consider the data tree: 512*5772Sas200622 * 513*5772Sas200622 * +--------+ 514*5772Sas200622 * | user | 515*5772Sas200622 * +--------+ 516*5772Sas200622 * | name ----> "fred" (the string is a different OUTER) 517*5772Sas200622 * | uid | 518*5772Sas200622 * | gid | 519*5772Sas200622 * | n_gids | for example, 3 520*5772Sas200622 * | gids[0]| 521*5772Sas200622 * | gids[1]| 522*5772Sas200622 * | gids[2]| 523*5772Sas200622 * +--------+ 524*5772Sas200622 * 525*5772Sas200622 * The OUTER construct in the Stub Data would be: 526*5772Sas200622 * 527*5772Sas200622 * +---+---------+---------------------------------------------+ 528*5772Sas200622 * |pad|size_is=3 name uid gid n_gids=3 gids[0] gids[1] gids[2]| 529*5772Sas200622 * +---+---------+---------------------------------------------+ 530*5772Sas200622 * szing hdr|user |<-------------- user.cred ------------>| 531*5772Sas200622 * |<--- fixed-size ---->|<----- conformant ---->| 532*5772Sas200622 * 533*5772Sas200622 * The ndr_typeinfo for struct user will have: 534*5772Sas200622 * pdu_fixed_size_part = 16 four long words (name uid gid n_gids) 535*5772Sas200622 * pdu_variable_size_part = 4 per element, sizeof gids[0] 536*5772Sas200622 * 537*5772Sas200622 * VARYING CONSTRUCTS -- NOT IMPLEMENTED 538*5772Sas200622 * 539*5772Sas200622 * VARYING constructs have the following header: 540*5772Sas200622 * 541*5772Sas200622 * struct varying_header { 542*5772Sas200622 * ulong first_is; 543*5772Sas200622 * ulong length_is; 544*5772Sas200622 * }; 545*5772Sas200622 * 546*5772Sas200622 * This indicates which interval of an array is significant. 547*5772Sas200622 * Non-intersecting elements of the array are undefined and usually 548*5772Sas200622 * zero-filled. The first_is parameter for C arrays is always 0 for 549*5772Sas200622 * the first element. 550*5772Sas200622 * 551*5772Sas200622 * N.B. Constructs may contain one CONFORMANT element, which is always 552*5772Sas200622 * last, but may contain many VARYING elements, which can be anywhere. 553*5772Sas200622 * 554*5772Sas200622 * VARYING CONFORMANT constructs have the sizing headers arranged like 555*5772Sas200622 * this: 556*5772Sas200622 * 557*5772Sas200622 * struct conformant_header all_conformant[N_CONFORMANT_DIM]; 558*5772Sas200622 * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS]; 559*5772Sas200622 * 560*5772Sas200622 * The sizing header is immediately followed by the values for the 561*5772Sas200622 * construct. Again, we don't support more than one dimension and 562*5772Sas200622 * we don't support VARYING constructs at this time. 563*5772Sas200622 * 564*5772Sas200622 * A good example of a VARYING/CONFORMANT data structure is the UNIX 565*5772Sas200622 * directory entry: 566*5772Sas200622 * 567*5772Sas200622 * struct dirent { 568*5772Sas200622 * ushort reclen; 569*5772Sas200622 * ushort namlen; 570*5772Sas200622 * ulong inum; 571*5772Sas200622 * [size_is(reclen-8) length_is(namlen+1)] // -(2+2+4), +1 for NUL 572*5772Sas200622 * uchar name[*]; 573*5772Sas200622 * }; 574*5772Sas200622 * 575*5772Sas200622 * 576*5772Sas200622 * STRINGS ARE A SPECIAL CASE 577*5772Sas200622 * 578*5772Sas200622 * Strings are handled specially. MS/RPC uses VARYING/CONFORMANT structures 579*5772Sas200622 * for strings. This is a simple one-dimensional variable-length array, 580*5772Sas200622 * typically with its last element all zeroes. We handle strings with the 581*5772Sas200622 * header: 582*5772Sas200622 * 583*5772Sas200622 * struct string_header { 584*5772Sas200622 * ulong size_is; 585*5772Sas200622 * ulong first_is; // always 0 586*5772Sas200622 * ulong length_is; // always same as size_is 587*5772Sas200622 * }; 588*5772Sas200622 * 589*5772Sas200622 * If general support for VARYING and VARYING/CONFORMANT mechanisms is 590*5772Sas200622 * implemented, we probably won't need the strings special case. 591*5772Sas200622 */ 592*5772Sas200622 int 593*5772Sas200622 mlndr_outer(struct ndr_reference *outer_ref) 594*5772Sas200622 { 595*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 596*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 597*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 598*5772Sas200622 int is_union = NDR_IS_UNION(ti); 599*5772Sas200622 int is_string = NDR_IS_STRING(ti); 600*5772Sas200622 int error = NDR_ERR_OUTER_PARAMS_BAD; 601*5772Sas200622 int params; 602*5772Sas200622 603*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 604*5772Sas200622 605*5772Sas200622 NDR_TATTLE(outer_ref, "--OUTER--"); 606*5772Sas200622 607*5772Sas200622 /* All outer constructs start on a mod4 (longword) boundary */ 608*5772Sas200622 if (!mlndr_outer_align(outer_ref)) 609*5772Sas200622 return (0); /* error already set */ 610*5772Sas200622 611*5772Sas200622 /* Regardless of what it is, this is where it starts */ 612*5772Sas200622 outer_ref->pdu_offset = mlnds->pdu_scan_offset; 613*5772Sas200622 614*5772Sas200622 if (is_union) { 615*5772Sas200622 error = NDR_ERR_OUTER_UNION_ILLEGAL; 616*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 617*5772Sas200622 return (0); 618*5772Sas200622 } 619*5772Sas200622 620*5772Sas200622 switch (params) { 621*5772Sas200622 case NDR_F_NONE: 622*5772Sas200622 if (is_string) 623*5772Sas200622 return (mlndr_outer_string(outer_ref)); 624*5772Sas200622 if (is_varlen) 625*5772Sas200622 return (mlndr_outer_conformant_construct(outer_ref)); 626*5772Sas200622 627*5772Sas200622 return (mlndr_outer_fixed(outer_ref)); 628*5772Sas200622 break; 629*5772Sas200622 630*5772Sas200622 case NDR_F_SIZE_IS: 631*5772Sas200622 case NDR_F_DIMENSION_IS: 632*5772Sas200622 if (is_varlen) { 633*5772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 634*5772Sas200622 break; 635*5772Sas200622 } 636*5772Sas200622 637*5772Sas200622 if (params == NDR_F_SIZE_IS) 638*5772Sas200622 return (mlndr_outer_conformant_array(outer_ref)); 639*5772Sas200622 else 640*5772Sas200622 return (mlndr_outer_fixed_array(outer_ref)); 641*5772Sas200622 break; 642*5772Sas200622 643*5772Sas200622 default: 644*5772Sas200622 error = NDR_ERR_OUTER_PARAMS_BAD; 645*5772Sas200622 break; 646*5772Sas200622 } 647*5772Sas200622 648*5772Sas200622 /* 649*5772Sas200622 * If we get here, something is wrong. Most likely, 650*5772Sas200622 * the params flags do not match. 651*5772Sas200622 */ 652*5772Sas200622 NDR_SET_ERROR(outer_ref, error); 653*5772Sas200622 return (0); 654*5772Sas200622 } 655*5772Sas200622 656*5772Sas200622 int 657*5772Sas200622 mlndr_outer_fixed(struct ndr_reference *outer_ref) 658*5772Sas200622 { 659*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 660*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 661*5772Sas200622 struct ndr_reference myref; 662*5772Sas200622 char *valp = NULL; 663*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 664*5772Sas200622 int is_union = NDR_IS_UNION(ti); 665*5772Sas200622 int is_string = NDR_IS_STRING(ti); 666*5772Sas200622 int rc; 667*5772Sas200622 unsigned n_hdr; 668*5772Sas200622 unsigned n_fixed; 669*5772Sas200622 unsigned n_variable; 670*5772Sas200622 unsigned n_alloc; 671*5772Sas200622 unsigned n_pdu_total; 672*5772Sas200622 int params; 673*5772Sas200622 674*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 675*5772Sas200622 676*5772Sas200622 assert(!is_varlen && !is_string && !is_union); 677*5772Sas200622 assert(params == NDR_F_NONE); 678*5772Sas200622 679*5772Sas200622 /* no header for this */ 680*5772Sas200622 n_hdr = 0; 681*5772Sas200622 682*5772Sas200622 /* fixed part -- exactly one of these */ 683*5772Sas200622 n_fixed = ti->pdu_size_fixed_part; 684*5772Sas200622 assert(n_fixed > 0); 685*5772Sas200622 686*5772Sas200622 /* variable part -- exactly none of these */ 687*5772Sas200622 n_variable = 0; 688*5772Sas200622 689*5772Sas200622 /* sum them up to determine the PDU space required */ 690*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 691*5772Sas200622 692*5772Sas200622 /* similar sum to determine how much local memory is required */ 693*5772Sas200622 n_alloc = n_fixed + n_variable; 694*5772Sas200622 695*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 696*5772Sas200622 if (!rc) 697*5772Sas200622 return (rc); /* error already set */ 698*5772Sas200622 699*5772Sas200622 switch (mlnds->m_op) { 700*5772Sas200622 case NDR_M_OP_MARSHALL: 701*5772Sas200622 valp = outer_ref->datum; 702*5772Sas200622 assert(valp); 703*5772Sas200622 if (outer_ref->backptr) { 704*5772Sas200622 assert(valp == *outer_ref->backptr); 705*5772Sas200622 } 706*5772Sas200622 break; 707*5772Sas200622 708*5772Sas200622 case NDR_M_OP_UNMARSHALL: 709*5772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 710*5772Sas200622 if (!valp) { 711*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 712*5772Sas200622 return (0); 713*5772Sas200622 } 714*5772Sas200622 if (outer_ref->backptr) 715*5772Sas200622 *outer_ref->backptr = valp; 716*5772Sas200622 outer_ref->datum = valp; 717*5772Sas200622 break; 718*5772Sas200622 719*5772Sas200622 default: 720*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 721*5772Sas200622 return (0); 722*5772Sas200622 } 723*5772Sas200622 724*5772Sas200622 bzero(&myref, sizeof (myref)); 725*5772Sas200622 myref.stream = mlnds; 726*5772Sas200622 myref.enclosing = outer_ref; 727*5772Sas200622 myref.ti = outer_ref->ti; 728*5772Sas200622 myref.datum = outer_ref->datum; 729*5772Sas200622 myref.name = "FIXED-VALUE"; 730*5772Sas200622 myref.outer_flags = NDR_F_NONE; 731*5772Sas200622 myref.inner_flags = NDR_F_NONE; 732*5772Sas200622 733*5772Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 734*5772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 735*5772Sas200622 736*5772Sas200622 rc = mlndr_inner(&myref); 737*5772Sas200622 if (!rc) 738*5772Sas200622 return (rc); /* error already set */ 739*5772Sas200622 740*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 741*5772Sas200622 return (1); 742*5772Sas200622 } 743*5772Sas200622 744*5772Sas200622 int 745*5772Sas200622 mlndr_outer_fixed_array(struct ndr_reference *outer_ref) 746*5772Sas200622 { 747*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 748*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 749*5772Sas200622 struct ndr_reference myref; 750*5772Sas200622 char *valp = NULL; 751*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 752*5772Sas200622 int is_union = NDR_IS_UNION(ti); 753*5772Sas200622 int is_string = NDR_IS_STRING(ti); 754*5772Sas200622 int rc; 755*5772Sas200622 unsigned n_hdr; 756*5772Sas200622 unsigned n_fixed; 757*5772Sas200622 unsigned n_variable; 758*5772Sas200622 unsigned n_alloc; 759*5772Sas200622 unsigned n_pdu_total; 760*5772Sas200622 int params; 761*5772Sas200622 762*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 763*5772Sas200622 764*5772Sas200622 assert(!is_varlen && !is_string && !is_union); 765*5772Sas200622 assert(params == NDR_F_DIMENSION_IS); 766*5772Sas200622 767*5772Sas200622 /* no header for this */ 768*5772Sas200622 n_hdr = 0; 769*5772Sas200622 770*5772Sas200622 /* fixed part -- exactly dimension_is of these */ 771*5772Sas200622 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is; 772*5772Sas200622 assert(n_fixed > 0); 773*5772Sas200622 774*5772Sas200622 /* variable part -- exactly none of these */ 775*5772Sas200622 n_variable = 0; 776*5772Sas200622 777*5772Sas200622 /* sum them up to determine the PDU space required */ 778*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 779*5772Sas200622 780*5772Sas200622 /* similar sum to determine how much local memory is required */ 781*5772Sas200622 n_alloc = n_fixed + n_variable; 782*5772Sas200622 783*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 784*5772Sas200622 if (!rc) 785*5772Sas200622 return (rc); /* error already set */ 786*5772Sas200622 787*5772Sas200622 switch (mlnds->m_op) { 788*5772Sas200622 case NDR_M_OP_MARSHALL: 789*5772Sas200622 valp = outer_ref->datum; 790*5772Sas200622 assert(valp); 791*5772Sas200622 if (outer_ref->backptr) { 792*5772Sas200622 assert(valp == *outer_ref->backptr); 793*5772Sas200622 } 794*5772Sas200622 break; 795*5772Sas200622 796*5772Sas200622 case NDR_M_OP_UNMARSHALL: 797*5772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 798*5772Sas200622 if (!valp) { 799*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 800*5772Sas200622 return (0); 801*5772Sas200622 } 802*5772Sas200622 if (outer_ref->backptr) 803*5772Sas200622 *outer_ref->backptr = valp; 804*5772Sas200622 outer_ref->datum = valp; 805*5772Sas200622 break; 806*5772Sas200622 807*5772Sas200622 default: 808*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 809*5772Sas200622 return (0); 810*5772Sas200622 } 811*5772Sas200622 812*5772Sas200622 bzero(&myref, sizeof (myref)); 813*5772Sas200622 myref.stream = mlnds; 814*5772Sas200622 myref.enclosing = outer_ref; 815*5772Sas200622 myref.ti = outer_ref->ti; 816*5772Sas200622 myref.datum = outer_ref->datum; 817*5772Sas200622 myref.name = "FIXED-ARRAY"; 818*5772Sas200622 myref.outer_flags = NDR_F_NONE; 819*5772Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS; 820*5772Sas200622 myref.dimension_is = outer_ref->dimension_is; 821*5772Sas200622 822*5772Sas200622 myref.pdu_offset = outer_ref->pdu_offset; 823*5772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 824*5772Sas200622 825*5772Sas200622 rc = mlndr_inner(&myref); 826*5772Sas200622 if (!rc) 827*5772Sas200622 return (rc); /* error already set */ 828*5772Sas200622 829*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 830*5772Sas200622 return (1); 831*5772Sas200622 } 832*5772Sas200622 833*5772Sas200622 int 834*5772Sas200622 mlndr_outer_conformant_array(struct ndr_reference *outer_ref) 835*5772Sas200622 { 836*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 837*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 838*5772Sas200622 struct ndr_reference myref; 839*5772Sas200622 char *valp = NULL; 840*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 841*5772Sas200622 int is_union = NDR_IS_UNION(ti); 842*5772Sas200622 int is_string = NDR_IS_STRING(ti); 843*5772Sas200622 unsigned long size_is; 844*5772Sas200622 int rc; 845*5772Sas200622 unsigned n_hdr; 846*5772Sas200622 unsigned n_fixed; 847*5772Sas200622 unsigned n_variable; 848*5772Sas200622 unsigned n_alloc; 849*5772Sas200622 unsigned n_pdu_total; 850*5772Sas200622 int params; 851*5772Sas200622 852*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 853*5772Sas200622 854*5772Sas200622 assert(!is_varlen && !is_string && !is_union); 855*5772Sas200622 assert(params == NDR_F_SIZE_IS); 856*5772Sas200622 857*5772Sas200622 /* conformant header for this */ 858*5772Sas200622 n_hdr = 4; 859*5772Sas200622 860*5772Sas200622 /* fixed part -- exactly none of these */ 861*5772Sas200622 n_fixed = 0; 862*5772Sas200622 863*5772Sas200622 /* variable part -- exactly size_of of these */ 864*5772Sas200622 /* notice that it is the **fixed** size of the ti */ 865*5772Sas200622 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is; 866*5772Sas200622 867*5772Sas200622 /* sum them up to determine the PDU space required */ 868*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 869*5772Sas200622 870*5772Sas200622 /* similar sum to determine how much local memory is required */ 871*5772Sas200622 n_alloc = n_fixed + n_variable; 872*5772Sas200622 873*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 874*5772Sas200622 if (!rc) 875*5772Sas200622 return (rc); /* error already set */ 876*5772Sas200622 877*5772Sas200622 switch (mlnds->m_op) { 878*5772Sas200622 case NDR_M_OP_MARSHALL: 879*5772Sas200622 size_is = outer_ref->size_is; 880*5772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 881*5772Sas200622 if (!rc) 882*5772Sas200622 return (0); /* error already set */ 883*5772Sas200622 884*5772Sas200622 valp = outer_ref->datum; 885*5772Sas200622 assert(valp); 886*5772Sas200622 if (outer_ref->backptr) { 887*5772Sas200622 assert(valp == *outer_ref->backptr); 888*5772Sas200622 } 889*5772Sas200622 break; 890*5772Sas200622 891*5772Sas200622 case NDR_M_OP_UNMARSHALL: 892*5772Sas200622 rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is); 893*5772Sas200622 if (!rc) 894*5772Sas200622 return (0); /* error already set */ 895*5772Sas200622 896*5772Sas200622 if (size_is != outer_ref->size_is) { 897*5772Sas200622 NDR_SET_ERROR(outer_ref, 898*5772Sas200622 NDR_ERR_SIZE_IS_MISMATCH_PDU); 899*5772Sas200622 return (0); 900*5772Sas200622 } 901*5772Sas200622 902*5772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 903*5772Sas200622 if (!valp) { 904*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 905*5772Sas200622 return (0); 906*5772Sas200622 } 907*5772Sas200622 if (outer_ref->backptr) 908*5772Sas200622 *outer_ref->backptr = valp; 909*5772Sas200622 outer_ref->datum = valp; 910*5772Sas200622 break; 911*5772Sas200622 912*5772Sas200622 default: 913*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 914*5772Sas200622 return (0); 915*5772Sas200622 } 916*5772Sas200622 917*5772Sas200622 bzero(&myref, sizeof (myref)); 918*5772Sas200622 myref.stream = mlnds; 919*5772Sas200622 myref.enclosing = outer_ref; 920*5772Sas200622 myref.ti = outer_ref->ti; 921*5772Sas200622 myref.datum = outer_ref->datum; 922*5772Sas200622 myref.name = "CONFORMANT-ARRAY"; 923*5772Sas200622 myref.outer_flags = NDR_F_NONE; 924*5772Sas200622 myref.inner_flags = NDR_F_SIZE_IS; 925*5772Sas200622 myref.size_is = outer_ref->size_is; 926*5772Sas200622 927*5772Sas200622 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */ 928*5772Sas200622 myref.dimension_is = outer_ref->size_is; /* convenient */ 929*5772Sas200622 930*5772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4; 931*5772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 932*5772Sas200622 933*5772Sas200622 outer_ref->type_flags = NDR_F_NONE; 934*5772Sas200622 outer_ref->inner_flags = NDR_F_NONE; 935*5772Sas200622 936*5772Sas200622 rc = mlndr_inner(&myref); 937*5772Sas200622 if (!rc) 938*5772Sas200622 return (rc); /* error already set */ 939*5772Sas200622 940*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 941*5772Sas200622 return (1); 942*5772Sas200622 } 943*5772Sas200622 944*5772Sas200622 int 945*5772Sas200622 mlndr_outer_conformant_construct(struct ndr_reference *outer_ref) 946*5772Sas200622 { 947*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 948*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 949*5772Sas200622 struct ndr_reference myref; 950*5772Sas200622 char *valp = NULL; 951*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 952*5772Sas200622 int is_union = NDR_IS_UNION(ti); 953*5772Sas200622 int is_string = NDR_IS_STRING(ti); 954*5772Sas200622 unsigned long size_is; 955*5772Sas200622 int rc; 956*5772Sas200622 unsigned n_hdr; 957*5772Sas200622 unsigned n_fixed; 958*5772Sas200622 unsigned n_variable; 959*5772Sas200622 unsigned n_alloc; 960*5772Sas200622 unsigned n_pdu_total; 961*5772Sas200622 int params; 962*5772Sas200622 963*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 964*5772Sas200622 965*5772Sas200622 assert(is_varlen && !is_string && !is_union); 966*5772Sas200622 assert(params == NDR_F_NONE); 967*5772Sas200622 968*5772Sas200622 /* conformant header for this */ 969*5772Sas200622 n_hdr = 4; 970*5772Sas200622 971*5772Sas200622 /* fixed part -- exactly one of these */ 972*5772Sas200622 n_fixed = ti->pdu_size_fixed_part; 973*5772Sas200622 974*5772Sas200622 /* variable part -- exactly size_of of these */ 975*5772Sas200622 n_variable = 0; /* 0 for the moment */ 976*5772Sas200622 977*5772Sas200622 /* sum them up to determine the PDU space required */ 978*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 979*5772Sas200622 980*5772Sas200622 /* similar sum to determine how much local memory is required */ 981*5772Sas200622 n_alloc = n_fixed + n_variable; 982*5772Sas200622 983*5772Sas200622 /* For the moment, grow enough for the fixed-size part */ 984*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 985*5772Sas200622 if (!rc) 986*5772Sas200622 return (rc); /* error already set */ 987*5772Sas200622 988*5772Sas200622 switch (mlnds->m_op) { 989*5772Sas200622 case NDR_M_OP_MARSHALL: 990*5772Sas200622 /* 991*5772Sas200622 * We don't know the size yet. We have to wait for 992*5772Sas200622 * it. Proceed with the fixed-size part, and await 993*5772Sas200622 * the call to mlndr_size_is(). 994*5772Sas200622 */ 995*5772Sas200622 size_is = 0; 996*5772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 997*5772Sas200622 if (!rc) 998*5772Sas200622 return (0); /* error already set */ 999*5772Sas200622 1000*5772Sas200622 valp = outer_ref->datum; 1001*5772Sas200622 assert(valp); 1002*5772Sas200622 if (outer_ref->backptr) { 1003*5772Sas200622 assert(valp == *outer_ref->backptr); 1004*5772Sas200622 } 1005*5772Sas200622 break; 1006*5772Sas200622 1007*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1008*5772Sas200622 /* 1009*5772Sas200622 * We know the size of the variable part because 1010*5772Sas200622 * of the CONFORMANT header. We will verify 1011*5772Sas200622 * the header against the [size_is(X)] advice 1012*5772Sas200622 * later when mlndr_size_is() is called. 1013*5772Sas200622 */ 1014*5772Sas200622 rc = mlndr_outer_peek_sizing(outer_ref, 0, &size_is); 1015*5772Sas200622 if (!rc) 1016*5772Sas200622 return (0); /* error already set */ 1017*5772Sas200622 1018*5772Sas200622 /* recalculate metrics */ 1019*5772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 1020*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1021*5772Sas200622 n_alloc = n_fixed + n_variable; 1022*5772Sas200622 1023*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 1024*5772Sas200622 if (!rc) 1025*5772Sas200622 return (rc); /* error already set */ 1026*5772Sas200622 1027*5772Sas200622 outer_ref->size_is = size_is; /* verified later */ 1028*5772Sas200622 1029*5772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 1030*5772Sas200622 if (!valp) { 1031*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1032*5772Sas200622 return (0); 1033*5772Sas200622 } 1034*5772Sas200622 if (outer_ref->backptr) 1035*5772Sas200622 *outer_ref->backptr = valp; 1036*5772Sas200622 outer_ref->datum = valp; 1037*5772Sas200622 break; 1038*5772Sas200622 1039*5772Sas200622 default: 1040*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1041*5772Sas200622 return (0); 1042*5772Sas200622 } 1043*5772Sas200622 1044*5772Sas200622 bzero(&myref, sizeof (myref)); 1045*5772Sas200622 myref.stream = mlnds; 1046*5772Sas200622 myref.enclosing = outer_ref; 1047*5772Sas200622 myref.ti = outer_ref->ti; 1048*5772Sas200622 myref.datum = outer_ref->datum; 1049*5772Sas200622 myref.name = "CONFORMANT-CONSTRUCT"; 1050*5772Sas200622 myref.outer_flags = NDR_F_NONE; 1051*5772Sas200622 myref.inner_flags = NDR_F_NONE; 1052*5772Sas200622 myref.size_is = outer_ref->size_is; 1053*5772Sas200622 1054*5772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 4; 1055*5772Sas200622 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total; 1056*5772Sas200622 1057*5772Sas200622 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */ 1058*5772Sas200622 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */ 1059*5772Sas200622 1060*5772Sas200622 rc = mlndr_inner(&myref); 1061*5772Sas200622 if (!rc) 1062*5772Sas200622 return (rc); /* error already set */ 1063*5772Sas200622 1064*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 1065*5772Sas200622 1066*5772Sas200622 if (outer_ref->inner_flags != NDR_F_SIZE_IS) { 1067*5772Sas200622 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER); 1068*5772Sas200622 return (0); 1069*5772Sas200622 } 1070*5772Sas200622 1071*5772Sas200622 return (1); 1072*5772Sas200622 } 1073*5772Sas200622 1074*5772Sas200622 int 1075*5772Sas200622 mlndr_size_is(struct ndr_reference *ref) 1076*5772Sas200622 { 1077*5772Sas200622 struct mlndr_stream *mlnds = ref->stream; 1078*5772Sas200622 struct ndr_reference *outer_ref = mlnds->outer_current; 1079*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 1080*5772Sas200622 unsigned long size_is; 1081*5772Sas200622 int rc; 1082*5772Sas200622 unsigned n_hdr; 1083*5772Sas200622 unsigned n_fixed; 1084*5772Sas200622 unsigned n_variable; 1085*5772Sas200622 unsigned n_pdu_total; 1086*5772Sas200622 1087*5772Sas200622 assert(ref->inner_flags & NDR_F_SIZE_IS); 1088*5772Sas200622 size_is = ref->size_is; 1089*5772Sas200622 1090*5772Sas200622 if (outer_ref->type_flags != NDR_F_SIZE_IS) { 1091*5772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED); 1092*5772Sas200622 return (0); 1093*5772Sas200622 } 1094*5772Sas200622 1095*5772Sas200622 if (outer_ref->inner_flags & NDR_F_SIZE_IS) { 1096*5772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED); 1097*5772Sas200622 return (0); 1098*5772Sas200622 } 1099*5772Sas200622 1100*5772Sas200622 /* repeat metrics, see mlndr_conformant_construct() above */ 1101*5772Sas200622 n_hdr = 4; 1102*5772Sas200622 n_fixed = ti->pdu_size_fixed_part; 1103*5772Sas200622 n_variable = size_is * ti->pdu_size_variable_part; 1104*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1105*5772Sas200622 1106*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 1107*5772Sas200622 if (!rc) 1108*5772Sas200622 return (rc); /* error already set */ 1109*5772Sas200622 1110*5772Sas200622 switch (mlnds->m_op) { 1111*5772Sas200622 case NDR_M_OP_MARSHALL: 1112*5772Sas200622 /* 1113*5772Sas200622 * We have to set the sizing header and extend 1114*5772Sas200622 * the size of the PDU (already done). 1115*5772Sas200622 */ 1116*5772Sas200622 rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is); 1117*5772Sas200622 if (!rc) 1118*5772Sas200622 return (0); /* error already set */ 1119*5772Sas200622 break; 1120*5772Sas200622 1121*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1122*5772Sas200622 /* 1123*5772Sas200622 * Allocation done during mlndr_conformant_construct(). 1124*5772Sas200622 * All we are doing here is verifying that the 1125*5772Sas200622 * intended size (ref->size_is) matches the sizing header. 1126*5772Sas200622 */ 1127*5772Sas200622 if (size_is != outer_ref->size_is) { 1128*5772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU); 1129*5772Sas200622 return (0); 1130*5772Sas200622 } 1131*5772Sas200622 break; 1132*5772Sas200622 1133*5772Sas200622 default: 1134*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1135*5772Sas200622 return (0); 1136*5772Sas200622 } 1137*5772Sas200622 1138*5772Sas200622 outer_ref->inner_flags |= NDR_F_SIZE_IS; 1139*5772Sas200622 outer_ref->size_is = ref->size_is; 1140*5772Sas200622 return (1); 1141*5772Sas200622 } 1142*5772Sas200622 1143*5772Sas200622 int 1144*5772Sas200622 mlndr_outer_string(struct ndr_reference *outer_ref) 1145*5772Sas200622 { 1146*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 1147*5772Sas200622 struct ndr_typeinfo *ti = outer_ref->ti; 1148*5772Sas200622 struct ndr_reference myref; 1149*5772Sas200622 char *valp = NULL; 1150*5772Sas200622 unsigned is_varlen = ti->pdu_size_variable_part; 1151*5772Sas200622 int is_union = NDR_IS_UNION(ti); 1152*5772Sas200622 int is_string = NDR_IS_STRING(ti); 1153*5772Sas200622 int rc; 1154*5772Sas200622 unsigned n_zeroes; 1155*5772Sas200622 unsigned ix; 1156*5772Sas200622 unsigned long size_is; 1157*5772Sas200622 unsigned long first_is; 1158*5772Sas200622 unsigned long length_is; 1159*5772Sas200622 unsigned n_hdr; 1160*5772Sas200622 unsigned n_fixed; 1161*5772Sas200622 unsigned n_variable; 1162*5772Sas200622 unsigned n_alloc; 1163*5772Sas200622 unsigned n_pdu_total; 1164*5772Sas200622 int params; 1165*5772Sas200622 1166*5772Sas200622 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK; 1167*5772Sas200622 1168*5772Sas200622 assert(is_varlen && is_string && !is_union); 1169*5772Sas200622 assert(params == NDR_F_NONE); 1170*5772Sas200622 1171*5772Sas200622 /* string header for this: size_is first_is length_is */ 1172*5772Sas200622 n_hdr = 12; 1173*5772Sas200622 1174*5772Sas200622 /* fixed part -- exactly none of these */ 1175*5772Sas200622 n_fixed = 0; 1176*5772Sas200622 1177*5772Sas200622 if (!mlndr_outer_grow(outer_ref, n_hdr)) 1178*5772Sas200622 return (0); /* error already set */ 1179*5772Sas200622 1180*5772Sas200622 switch (mlnds->m_op) { 1181*5772Sas200622 case NDR_M_OP_MARSHALL: 1182*5772Sas200622 valp = outer_ref->datum; 1183*5772Sas200622 assert(valp); 1184*5772Sas200622 1185*5772Sas200622 if (outer_ref->backptr) 1186*5772Sas200622 assert(valp == *outer_ref->backptr); 1187*5772Sas200622 1188*5772Sas200622 if (ti == &ndt_s_wchar) { 1189*5772Sas200622 /* 1190*5772Sas200622 * size_is is the number of characters in the string, 1191*5772Sas200622 * including the null. We assume valp is UTF-8 encoded. 1192*5772Sas200622 * We can use mts_wcequiv_strlen for ASCII, extended 1193*5772Sas200622 * ASCII or Unicode (UCS-2). 1194*5772Sas200622 */ 1195*5772Sas200622 size_is = (mts_wcequiv_strlen(valp) / 1196*5772Sas200622 sizeof (mts_wchar_t)) + 1; 1197*5772Sas200622 1198*5772Sas200622 if (size_is > NDR_STRING_MAX) { 1199*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1200*5772Sas200622 return (0); 1201*5772Sas200622 } 1202*5772Sas200622 } else { 1203*5772Sas200622 valp = outer_ref->datum; 1204*5772Sas200622 n_zeroes = 0; 1205*5772Sas200622 for (ix = 0; ix < 1024; ix++) { 1206*5772Sas200622 if (valp[ix] == 0) { 1207*5772Sas200622 n_zeroes++; 1208*5772Sas200622 if (n_zeroes >= is_varlen && 1209*5772Sas200622 ix % is_varlen == 0) { 1210*5772Sas200622 break; 1211*5772Sas200622 } 1212*5772Sas200622 } else { 1213*5772Sas200622 n_zeroes = 0; 1214*5772Sas200622 } 1215*5772Sas200622 } 1216*5772Sas200622 if (ix >= 1024) { 1217*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1218*5772Sas200622 return (0); 1219*5772Sas200622 } 1220*5772Sas200622 size_is = ix+1; 1221*5772Sas200622 } 1222*5772Sas200622 1223*5772Sas200622 first_is = 0; 1224*5772Sas200622 1225*5772Sas200622 if (mlnds->flags & MLNDS_F_NOTERM) 1226*5772Sas200622 length_is = size_is - 1; 1227*5772Sas200622 else 1228*5772Sas200622 length_is = size_is; 1229*5772Sas200622 1230*5772Sas200622 if (!mlndr_outer_poke_sizing(outer_ref, 0, &size_is) || 1231*5772Sas200622 !mlndr_outer_poke_sizing(outer_ref, 4, &first_is) || 1232*5772Sas200622 !mlndr_outer_poke_sizing(outer_ref, 8, &length_is)) 1233*5772Sas200622 return (0); /* error already set */ 1234*5772Sas200622 break; 1235*5772Sas200622 1236*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1237*5772Sas200622 if (!mlndr_outer_peek_sizing(outer_ref, 0, &size_is) || 1238*5772Sas200622 !mlndr_outer_peek_sizing(outer_ref, 4, &first_is) || 1239*5772Sas200622 !mlndr_outer_peek_sizing(outer_ref, 8, &length_is)) 1240*5772Sas200622 return (0); /* error already set */ 1241*5772Sas200622 1242*5772Sas200622 /* 1243*5772Sas200622 * In addition to the first_is check, we used to check that 1244*5772Sas200622 * size_is or size_is-1 was equal to length_is but Windows95 1245*5772Sas200622 * doesn't conform to this "rule" (see variable part below). 1246*5772Sas200622 * The srvmgr tool for Windows95 sent the following values 1247*5772Sas200622 * for a path string: 1248*5772Sas200622 * 1249*5772Sas200622 * size_is = 261 (0x105) 1250*5772Sas200622 * first_is = 0 1251*5772Sas200622 * length_is = 53 (0x35) 1252*5772Sas200622 * 1253*5772Sas200622 * The length_is was correct (for the given path) but the 1254*5772Sas200622 * size_is was the maximum path length rather than being 1255*5772Sas200622 * related to length_is. 1256*5772Sas200622 */ 1257*5772Sas200622 if (first_is != 0) { 1258*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1259*5772Sas200622 return (0); 1260*5772Sas200622 } 1261*5772Sas200622 1262*5772Sas200622 if (ti == &ndt_s_wchar) { 1263*5772Sas200622 /* 1264*5772Sas200622 * Decoding Unicode to UTF-8; we need to allow 1265*5772Sas200622 * for the maximum possible char size. It would 1266*5772Sas200622 * be nice to use mbequiv_strlen but the string 1267*5772Sas200622 * may not be null terminated. 1268*5772Sas200622 */ 1269*5772Sas200622 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX; 1270*5772Sas200622 } else { 1271*5772Sas200622 n_alloc = (size_is + 1) * is_varlen; 1272*5772Sas200622 } 1273*5772Sas200622 1274*5772Sas200622 valp = MLNDS_MALLOC(mlnds, n_alloc, outer_ref); 1275*5772Sas200622 if (!valp) { 1276*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1277*5772Sas200622 return (0); 1278*5772Sas200622 } 1279*5772Sas200622 1280*5772Sas200622 bzero(valp, (size_is+1) * is_varlen); 1281*5772Sas200622 1282*5772Sas200622 if (outer_ref->backptr) 1283*5772Sas200622 *outer_ref->backptr = valp; 1284*5772Sas200622 outer_ref->datum = valp; 1285*5772Sas200622 break; 1286*5772Sas200622 1287*5772Sas200622 default: 1288*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1289*5772Sas200622 return (0); 1290*5772Sas200622 } 1291*5772Sas200622 1292*5772Sas200622 /* 1293*5772Sas200622 * Variable part - exactly length_is of these. 1294*5772Sas200622 * 1295*5772Sas200622 * Usually, length_is is same as size_is and includes nul. 1296*5772Sas200622 * Some protocols use length_is = size_is-1, and length_is does 1297*5772Sas200622 * not include the nul (which is more consistent with DCE spec). 1298*5772Sas200622 * If the length_is is 0, there is no data following the 1299*5772Sas200622 * sizing header, regardless of size_is. 1300*5772Sas200622 */ 1301*5772Sas200622 n_variable = length_is * is_varlen; 1302*5772Sas200622 1303*5772Sas200622 /* sum them up to determine the PDU space required */ 1304*5772Sas200622 n_pdu_total = n_hdr + n_fixed + n_variable; 1305*5772Sas200622 1306*5772Sas200622 /* similar sum to determine how much local memory is required */ 1307*5772Sas200622 n_alloc = n_fixed + n_variable; 1308*5772Sas200622 1309*5772Sas200622 rc = mlndr_outer_grow(outer_ref, n_pdu_total); 1310*5772Sas200622 if (!rc) 1311*5772Sas200622 return (rc); /* error already set */ 1312*5772Sas200622 1313*5772Sas200622 if (length_is > 0) { 1314*5772Sas200622 bzero(&myref, sizeof (myref)); 1315*5772Sas200622 myref.stream = mlnds; 1316*5772Sas200622 myref.enclosing = outer_ref; 1317*5772Sas200622 myref.ti = outer_ref->ti; 1318*5772Sas200622 myref.datum = outer_ref->datum; 1319*5772Sas200622 myref.name = "OUTER-STRING"; 1320*5772Sas200622 myref.outer_flags = NDR_F_IS_STRING; 1321*5772Sas200622 myref.inner_flags = NDR_F_NONE; 1322*5772Sas200622 1323*5772Sas200622 /* 1324*5772Sas200622 * Set up size_is and strlen_is for mlndr_s_wchar. 1325*5772Sas200622 */ 1326*5772Sas200622 myref.size_is = size_is; 1327*5772Sas200622 myref.strlen_is = length_is; 1328*5772Sas200622 } 1329*5772Sas200622 1330*5772Sas200622 myref.pdu_offset = outer_ref->pdu_offset + 12; 1331*5772Sas200622 1332*5772Sas200622 /* 1333*5772Sas200622 * Don't try to decode empty strings. 1334*5772Sas200622 */ 1335*5772Sas200622 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 1336*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 1337*5772Sas200622 return (1); 1338*5772Sas200622 } 1339*5772Sas200622 1340*5772Sas200622 if ((size_is != 0) && (length_is != 0)) { 1341*5772Sas200622 rc = mlndr_inner(&myref); 1342*5772Sas200622 if (!rc) 1343*5772Sas200622 return (rc); /* error already set */ 1344*5772Sas200622 } 1345*5772Sas200622 1346*5772Sas200622 mlnds->pdu_scan_offset = outer_ref->pdu_end_offset; 1347*5772Sas200622 return (1); 1348*5772Sas200622 } 1349*5772Sas200622 1350*5772Sas200622 int 1351*5772Sas200622 mlndr_outer_peek_sizing(struct ndr_reference *outer_ref, unsigned offset, 1352*5772Sas200622 unsigned long *sizing_p) 1353*5772Sas200622 { 1354*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 1355*5772Sas200622 unsigned long pdu_offset; 1356*5772Sas200622 int rc; 1357*5772Sas200622 1358*5772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 1359*5772Sas200622 1360*5772Sas200622 if (pdu_offset < mlnds->outer_current->pdu_offset || 1361*5772Sas200622 pdu_offset > mlnds->outer_current->pdu_end_offset || 1362*5772Sas200622 pdu_offset+4 > mlnds->outer_current->pdu_end_offset) { 1363*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1364*5772Sas200622 return (0); 1365*5772Sas200622 } 1366*5772Sas200622 1367*5772Sas200622 switch (mlnds->m_op) { 1368*5772Sas200622 case NDR_M_OP_MARSHALL: 1369*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1370*5772Sas200622 return (0); 1371*5772Sas200622 1372*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1373*5772Sas200622 rc = MLNDS_GET_PDU(mlnds, pdu_offset, 4, (char *)sizing_p, 1374*5772Sas200622 mlnds->swap, outer_ref); 1375*5772Sas200622 break; 1376*5772Sas200622 1377*5772Sas200622 default: 1378*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1379*5772Sas200622 return (0); 1380*5772Sas200622 } 1381*5772Sas200622 1382*5772Sas200622 return (rc); 1383*5772Sas200622 } 1384*5772Sas200622 1385*5772Sas200622 int 1386*5772Sas200622 mlndr_outer_poke_sizing(struct ndr_reference *outer_ref, unsigned offset, 1387*5772Sas200622 unsigned long *sizing_p) 1388*5772Sas200622 { 1389*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 1390*5772Sas200622 unsigned long pdu_offset; 1391*5772Sas200622 int rc; 1392*5772Sas200622 1393*5772Sas200622 pdu_offset = outer_ref->pdu_offset + offset; 1394*5772Sas200622 1395*5772Sas200622 if (pdu_offset < mlnds->outer_current->pdu_offset || 1396*5772Sas200622 pdu_offset > mlnds->outer_current->pdu_end_offset || 1397*5772Sas200622 pdu_offset+4 > mlnds->outer_current->pdu_end_offset) { 1398*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1399*5772Sas200622 return (0); 1400*5772Sas200622 } 1401*5772Sas200622 1402*5772Sas200622 switch (mlnds->m_op) { 1403*5772Sas200622 case NDR_M_OP_MARSHALL: 1404*5772Sas200622 rc = MLNDS_PUT_PDU(mlnds, pdu_offset, 4, (char *)sizing_p, 1405*5772Sas200622 mlnds->swap, outer_ref); 1406*5772Sas200622 break; 1407*5772Sas200622 1408*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1409*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1410*5772Sas200622 return (0); 1411*5772Sas200622 1412*5772Sas200622 default: 1413*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1414*5772Sas200622 return (0); 1415*5772Sas200622 } 1416*5772Sas200622 1417*5772Sas200622 return (rc); 1418*5772Sas200622 } 1419*5772Sas200622 1420*5772Sas200622 /* 1421*5772Sas200622 * All OUTER constructs begin on a mod4 (dword) boundary - except 1422*5772Sas200622 * for the ones that don't: some MSRPC calls appear to use word or 1423*5772Sas200622 * packed alignment. Strings appear to be dword aligned. 1424*5772Sas200622 */ 1425*5772Sas200622 int 1426*5772Sas200622 mlndr_outer_align(struct ndr_reference *outer_ref) 1427*5772Sas200622 { 1428*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 1429*5772Sas200622 int rc; 1430*5772Sas200622 unsigned n_pad; 1431*5772Sas200622 unsigned align; 1432*5772Sas200622 1433*5772Sas200622 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 1434*5772Sas200622 align = outer_ref->ti->alignment; 1435*5772Sas200622 n_pad = ((align + 1) - mlnds->pdu_scan_offset) & align; 1436*5772Sas200622 } else { 1437*5772Sas200622 n_pad = (4 - mlnds->pdu_scan_offset) & 3; 1438*5772Sas200622 } 1439*5772Sas200622 1440*5772Sas200622 if (n_pad == 0) 1441*5772Sas200622 return (1); /* already aligned, often the case */ 1442*5772Sas200622 1443*5772Sas200622 if (!mlndr_outer_grow(outer_ref, n_pad)) 1444*5772Sas200622 return (0); /* error already set */ 1445*5772Sas200622 1446*5772Sas200622 switch (mlnds->m_op) { 1447*5772Sas200622 case NDR_M_OP_MARSHALL: 1448*5772Sas200622 rc = MLNDS_PAD_PDU(mlnds, 1449*5772Sas200622 mlnds->pdu_scan_offset, n_pad, outer_ref); 1450*5772Sas200622 if (!rc) { 1451*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 1452*5772Sas200622 return (0); 1453*5772Sas200622 } 1454*5772Sas200622 break; 1455*5772Sas200622 1456*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1457*5772Sas200622 break; 1458*5772Sas200622 1459*5772Sas200622 default: 1460*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1461*5772Sas200622 return (0); 1462*5772Sas200622 } 1463*5772Sas200622 1464*5772Sas200622 mlnds->pdu_scan_offset += n_pad; 1465*5772Sas200622 return (1); 1466*5772Sas200622 } 1467*5772Sas200622 1468*5772Sas200622 int 1469*5772Sas200622 mlndr_outer_grow(struct ndr_reference *outer_ref, unsigned n_total) 1470*5772Sas200622 { 1471*5772Sas200622 struct mlndr_stream *mlnds = outer_ref->stream; 1472*5772Sas200622 unsigned long pdu_want_size; 1473*5772Sas200622 int rc, is_ok = 0; 1474*5772Sas200622 1475*5772Sas200622 pdu_want_size = mlnds->pdu_scan_offset + n_total; 1476*5772Sas200622 1477*5772Sas200622 if (pdu_want_size <= mlnds->pdu_max_size) { 1478*5772Sas200622 is_ok = 1; 1479*5772Sas200622 } 1480*5772Sas200622 1481*5772Sas200622 switch (mlnds->m_op) { 1482*5772Sas200622 case NDR_M_OP_MARSHALL: 1483*5772Sas200622 if (is_ok) 1484*5772Sas200622 break; 1485*5772Sas200622 rc = MLNDS_GROW_PDU(mlnds, pdu_want_size, outer_ref); 1486*5772Sas200622 if (!rc) { 1487*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 1488*5772Sas200622 return (0); 1489*5772Sas200622 } 1490*5772Sas200622 break; 1491*5772Sas200622 1492*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1493*5772Sas200622 if (is_ok) 1494*5772Sas200622 break; 1495*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 1496*5772Sas200622 return (0); 1497*5772Sas200622 1498*5772Sas200622 default: 1499*5772Sas200622 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1500*5772Sas200622 return (0); 1501*5772Sas200622 } 1502*5772Sas200622 1503*5772Sas200622 if (mlnds->pdu_size < pdu_want_size) 1504*5772Sas200622 mlnds->pdu_size = pdu_want_size; 1505*5772Sas200622 1506*5772Sas200622 outer_ref->pdu_end_offset = pdu_want_size; 1507*5772Sas200622 return (1); 1508*5772Sas200622 } 1509*5772Sas200622 1510*5772Sas200622 /* 1511*5772Sas200622 * INNER ELEMENTS 1512*5772Sas200622 * 1513*5772Sas200622 * The local datum (arg_ref->datum) already exists, there is no need to 1514*5772Sas200622 * malloc() it. The datum should point at a member of a structure. 1515*5772Sas200622 * 1516*5772Sas200622 * For the most part, mlndr_inner() and its helpers are just a sanity 1517*5772Sas200622 * check. The underlying ti->ndr_func() could be called immediately 1518*5772Sas200622 * for non-pointer elements. For the sake of robustness, we detect 1519*5772Sas200622 * run-time errors here. Most of the situations this protects against 1520*5772Sas200622 * have already been checked by the IDL compiler. This is also a 1521*5772Sas200622 * common point for processing of all data, and so is a convenient 1522*5772Sas200622 * place to work from for debugging. 1523*5772Sas200622 */ 1524*5772Sas200622 int 1525*5772Sas200622 mlndr_inner(struct ndr_reference *arg_ref) 1526*5772Sas200622 { 1527*5772Sas200622 struct ndr_typeinfo *ti = arg_ref->ti; 1528*5772Sas200622 int is_varlen = ti->pdu_size_variable_part; 1529*5772Sas200622 int is_union = NDR_IS_UNION(ti); 1530*5772Sas200622 int error = NDR_ERR_INNER_PARAMS_BAD; 1531*5772Sas200622 int params; 1532*5772Sas200622 1533*5772Sas200622 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1534*5772Sas200622 1535*5772Sas200622 switch (params) { 1536*5772Sas200622 case NDR_F_NONE: 1537*5772Sas200622 if (is_union) { 1538*5772Sas200622 error = NDR_ERR_SWITCH_VALUE_MISSING; 1539*5772Sas200622 break; 1540*5772Sas200622 } 1541*5772Sas200622 return (*ti->ndr_func)(arg_ref); 1542*5772Sas200622 break; 1543*5772Sas200622 1544*5772Sas200622 case NDR_F_SIZE_IS: 1545*5772Sas200622 case NDR_F_DIMENSION_IS: 1546*5772Sas200622 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 1547*5772Sas200622 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 1548*5772Sas200622 if (is_varlen) { 1549*5772Sas200622 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 1550*5772Sas200622 break; 1551*5772Sas200622 } 1552*5772Sas200622 if (is_union) { 1553*5772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1554*5772Sas200622 break; 1555*5772Sas200622 } 1556*5772Sas200622 if (params & NDR_F_IS_POINTER) 1557*5772Sas200622 return (mlndr_inner_pointer(arg_ref)); 1558*5772Sas200622 else if (params & NDR_F_IS_REFERENCE) 1559*5772Sas200622 return (mlndr_inner_reference(arg_ref)); 1560*5772Sas200622 else 1561*5772Sas200622 return (mlndr_inner_array(arg_ref)); 1562*5772Sas200622 break; 1563*5772Sas200622 1564*5772Sas200622 case NDR_F_IS_POINTER: /* type is pointer to one something */ 1565*5772Sas200622 if (is_union) { 1566*5772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1567*5772Sas200622 break; 1568*5772Sas200622 } 1569*5772Sas200622 return (mlndr_inner_pointer(arg_ref)); 1570*5772Sas200622 break; 1571*5772Sas200622 1572*5772Sas200622 case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 1573*5772Sas200622 if (is_union) { 1574*5772Sas200622 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1575*5772Sas200622 break; 1576*5772Sas200622 } 1577*5772Sas200622 return (mlndr_inner_reference(arg_ref)); 1578*5772Sas200622 break; 1579*5772Sas200622 1580*5772Sas200622 case NDR_F_SWITCH_IS: 1581*5772Sas200622 if (!is_union) { 1582*5772Sas200622 error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 1583*5772Sas200622 break; 1584*5772Sas200622 } 1585*5772Sas200622 return (*ti->ndr_func)(arg_ref); 1586*5772Sas200622 break; 1587*5772Sas200622 1588*5772Sas200622 default: 1589*5772Sas200622 error = NDR_ERR_INNER_PARAMS_BAD; 1590*5772Sas200622 break; 1591*5772Sas200622 } 1592*5772Sas200622 1593*5772Sas200622 /* 1594*5772Sas200622 * If we get here, something is wrong. Most likely, 1595*5772Sas200622 * the params flags do not match 1596*5772Sas200622 */ 1597*5772Sas200622 NDR_SET_ERROR(arg_ref, error); 1598*5772Sas200622 return (0); 1599*5772Sas200622 } 1600*5772Sas200622 1601*5772Sas200622 int 1602*5772Sas200622 mlndr_inner_pointer(struct ndr_reference *arg_ref) 1603*5772Sas200622 { 1604*5772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 1605*5772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1606*5772Sas200622 char **valpp = (char **)arg_ref->datum; 1607*5772Sas200622 struct ndr_reference *outer_ref; 1608*5772Sas200622 1609*5772Sas200622 if (!mlndr__ulong(arg_ref)) 1610*5772Sas200622 return (0); /* error */ 1611*5772Sas200622 if (!*valpp) 1612*5772Sas200622 return (1); /* NULL pointer */ 1613*5772Sas200622 1614*5772Sas200622 outer_ref = mlndr_enter_outer_queue(arg_ref); 1615*5772Sas200622 if (!outer_ref) 1616*5772Sas200622 return (0); /* error already set */ 1617*5772Sas200622 1618*5772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 1619*5772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1620*5772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 1621*5772Sas200622 #ifdef NDR_INNER_NOT_YET 1622*5772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 1623*5772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1624*5772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1625*5772Sas200622 } 1626*5772Sas200622 #endif /* NDR_INNER_NOT_YET */ 1627*5772Sas200622 1628*5772Sas200622 outer_ref->backptr = valpp; 1629*5772Sas200622 1630*5772Sas200622 switch (mlnds->m_op) { 1631*5772Sas200622 case NDR_M_OP_MARSHALL: 1632*5772Sas200622 outer_ref->datum = *valpp; 1633*5772Sas200622 break; 1634*5772Sas200622 1635*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1636*5772Sas200622 /* 1637*5772Sas200622 * This is probably wrong if the application allocated 1638*5772Sas200622 * memory in advance. Indicate no value for now. 1639*5772Sas200622 * ONC RPC handles this case. 1640*5772Sas200622 */ 1641*5772Sas200622 *valpp = 0; 1642*5772Sas200622 outer_ref->datum = 0; 1643*5772Sas200622 break; 1644*5772Sas200622 } 1645*5772Sas200622 1646*5772Sas200622 return (1); /* pointer dereference scheduled */ 1647*5772Sas200622 } 1648*5772Sas200622 1649*5772Sas200622 int 1650*5772Sas200622 mlndr_inner_reference(struct ndr_reference *arg_ref) 1651*5772Sas200622 { 1652*5772Sas200622 struct mlndr_stream *mlnds = arg_ref->stream; 1653*5772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1654*5772Sas200622 char **valpp = (char **)arg_ref->datum; 1655*5772Sas200622 struct ndr_reference *outer_ref; 1656*5772Sas200622 1657*5772Sas200622 outer_ref = mlndr_enter_outer_queue(arg_ref); 1658*5772Sas200622 if (!outer_ref) 1659*5772Sas200622 return (0); /* error already set */ 1660*5772Sas200622 1661*5772Sas200622 /* move advice in inner_flags to outer_flags sans pointer */ 1662*5772Sas200622 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1663*5772Sas200622 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 1664*5772Sas200622 #ifdef NDR_INNER_REF_NOT_YET 1665*5772Sas200622 outer_ref->outer_flags |= NDR_F_BACKPTR; 1666*5772Sas200622 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1667*5772Sas200622 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1668*5772Sas200622 } 1669*5772Sas200622 #endif /* NDR_INNER_REF_NOT_YET */ 1670*5772Sas200622 1671*5772Sas200622 outer_ref->backptr = valpp; 1672*5772Sas200622 1673*5772Sas200622 switch (mlnds->m_op) { 1674*5772Sas200622 case NDR_M_OP_MARSHALL: 1675*5772Sas200622 outer_ref->datum = *valpp; 1676*5772Sas200622 break; 1677*5772Sas200622 1678*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1679*5772Sas200622 /* 1680*5772Sas200622 * This is probably wrong if the application allocated 1681*5772Sas200622 * memory in advance. Indicate no value for now. 1682*5772Sas200622 * ONC RPC handles this case. 1683*5772Sas200622 */ 1684*5772Sas200622 *valpp = 0; 1685*5772Sas200622 outer_ref->datum = 0; 1686*5772Sas200622 break; 1687*5772Sas200622 } 1688*5772Sas200622 1689*5772Sas200622 return (1); /* pointer dereference scheduled */ 1690*5772Sas200622 } 1691*5772Sas200622 1692*5772Sas200622 int 1693*5772Sas200622 mlndr_inner_array(struct ndr_reference *encl_ref) 1694*5772Sas200622 { 1695*5772Sas200622 struct ndr_typeinfo *ti = encl_ref->ti; 1696*5772Sas200622 struct ndr_reference myref; 1697*5772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 1698*5772Sas200622 unsigned long n_elem; 1699*5772Sas200622 unsigned long i; 1700*5772Sas200622 char name[30]; 1701*5772Sas200622 1702*5772Sas200622 if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 1703*5772Sas200622 /* now is the time to check/set size */ 1704*5772Sas200622 if (!mlndr_size_is(encl_ref)) 1705*5772Sas200622 return (0); /* error already set */ 1706*5772Sas200622 n_elem = encl_ref->size_is; 1707*5772Sas200622 } else { 1708*5772Sas200622 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 1709*5772Sas200622 n_elem = encl_ref->dimension_is; 1710*5772Sas200622 } 1711*5772Sas200622 1712*5772Sas200622 bzero(&myref, sizeof (myref)); 1713*5772Sas200622 myref.enclosing = encl_ref; 1714*5772Sas200622 myref.stream = encl_ref->stream; 1715*5772Sas200622 myref.packed_alignment = 0; 1716*5772Sas200622 myref.ti = ti; 1717*5772Sas200622 myref.inner_flags = NDR_F_NONE; 1718*5772Sas200622 1719*5772Sas200622 for (i = 0; i < n_elem; i++) { 1720*5772Sas200622 (void) sprintf(name, "[%lu]", i); 1721*5772Sas200622 myref.name = name; 1722*5772Sas200622 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 1723*5772Sas200622 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 1724*5772Sas200622 1725*5772Sas200622 if (!mlndr_inner(&myref)) 1726*5772Sas200622 return (0); 1727*5772Sas200622 } 1728*5772Sas200622 1729*5772Sas200622 return (1); 1730*5772Sas200622 } 1731*5772Sas200622 1732*5772Sas200622 1733*5772Sas200622 /* 1734*5772Sas200622 * BASIC TYPES 1735*5772Sas200622 */ 1736*5772Sas200622 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1737*5772Sas200622 extern int mlndr_##TYPE(struct ndr_reference *encl_ref); \ 1738*5772Sas200622 struct ndr_typeinfo ndt_##TYPE = { \ 1739*5772Sas200622 1, /* NDR version */ \ 1740*5772Sas200622 (SIZE)-1, /* alignment */ \ 1741*5772Sas200622 NDR_F_NONE, /* flags */ \ 1742*5772Sas200622 mlndr_##TYPE, /* ndr_func */ \ 1743*5772Sas200622 SIZE, /* pdu_size_fixed_part */ \ 1744*5772Sas200622 0, /* pdu_size_variable_part */ \ 1745*5772Sas200622 SIZE, /* c_size_fixed_part */ \ 1746*5772Sas200622 0, /* c_size_variable_part */ \ 1747*5772Sas200622 }; \ 1748*5772Sas200622 int mlndr_##TYPE(struct ndr_reference *ref) { \ 1749*5772Sas200622 return (mlndr_basic_integer(ref, SIZE)); \ 1750*5772Sas200622 } 1751*5772Sas200622 1752*5772Sas200622 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 1753*5772Sas200622 extern int mlndr_s##TYPE(struct ndr_reference *encl_ref); \ 1754*5772Sas200622 struct ndr_typeinfo ndt_s##TYPE = { \ 1755*5772Sas200622 1, /* NDR version */ \ 1756*5772Sas200622 (SIZE)-1, /* alignment */ \ 1757*5772Sas200622 NDR_F_STRING, /* flags */ \ 1758*5772Sas200622 mlndr_s##TYPE, /* ndr_func */ \ 1759*5772Sas200622 0, /* pdu_size_fixed_part */ \ 1760*5772Sas200622 SIZE, /* pdu_size_variable_part */ \ 1761*5772Sas200622 0, /* c_size_fixed_part */ \ 1762*5772Sas200622 SIZE, /* c_size_variable_part */ \ 1763*5772Sas200622 }; \ 1764*5772Sas200622 int mlndr_s##TYPE(struct ndr_reference *ref) { \ 1765*5772Sas200622 return (mlndr_string_basic_integer(ref, &ndt_##TYPE)); \ 1766*5772Sas200622 } 1767*5772Sas200622 1768*5772Sas200622 #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 1769*5772Sas200622 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1770*5772Sas200622 MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 1771*5772Sas200622 1772*5772Sas200622 extern int 1773*5772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size); 1774*5772Sas200622 1775*5772Sas200622 extern int 1776*5772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref, 1777*5772Sas200622 struct ndr_typeinfo *type_under); 1778*5772Sas200622 1779*5772Sas200622 1780*5772Sas200622 MAKE_BASIC_TYPE(_char, 1) 1781*5772Sas200622 MAKE_BASIC_TYPE(_uchar, 1) 1782*5772Sas200622 MAKE_BASIC_TYPE(_short, 2) 1783*5772Sas200622 MAKE_BASIC_TYPE(_ushort, 2) 1784*5772Sas200622 MAKE_BASIC_TYPE(_long, 4) 1785*5772Sas200622 MAKE_BASIC_TYPE(_ulong, 4) 1786*5772Sas200622 1787*5772Sas200622 MAKE_BASIC_TYPE_BASE(_wchar, 2) 1788*5772Sas200622 1789*5772Sas200622 int 1790*5772Sas200622 mlndr_basic_integer(struct ndr_reference *ref, unsigned size) 1791*5772Sas200622 { 1792*5772Sas200622 struct mlndr_stream *mlnds = ref->stream; 1793*5772Sas200622 char *valp = (char *)ref->datum; 1794*5772Sas200622 int rc; 1795*5772Sas200622 1796*5772Sas200622 switch (mlnds->m_op) { 1797*5772Sas200622 case NDR_M_OP_MARSHALL: 1798*5772Sas200622 rc = MLNDS_PUT_PDU(mlnds, ref->pdu_offset, size, 1799*5772Sas200622 valp, mlnds->swap, ref); 1800*5772Sas200622 break; 1801*5772Sas200622 1802*5772Sas200622 case NDR_M_OP_UNMARSHALL: 1803*5772Sas200622 rc = MLNDS_GET_PDU(mlnds, ref->pdu_offset, size, 1804*5772Sas200622 valp, mlnds->swap, ref); 1805*5772Sas200622 break; 1806*5772Sas200622 1807*5772Sas200622 default: 1808*5772Sas200622 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 1809*5772Sas200622 return (0); 1810*5772Sas200622 } 1811*5772Sas200622 1812*5772Sas200622 return (rc); 1813*5772Sas200622 } 1814*5772Sas200622 1815*5772Sas200622 int 1816*5772Sas200622 mlndr_string_basic_integer(struct ndr_reference *encl_ref, 1817*5772Sas200622 struct ndr_typeinfo *type_under) 1818*5772Sas200622 { 1819*5772Sas200622 unsigned long pdu_offset = encl_ref->pdu_offset; 1820*5772Sas200622 unsigned size = type_under->pdu_size_fixed_part; 1821*5772Sas200622 char *valp; 1822*5772Sas200622 struct ndr_reference myref; 1823*5772Sas200622 unsigned long i; 1824*5772Sas200622 long sense = 0; 1825*5772Sas200622 char name[30]; 1826*5772Sas200622 1827*5772Sas200622 assert(size != 0); 1828*5772Sas200622 1829*5772Sas200622 bzero(&myref, sizeof (myref)); 1830*5772Sas200622 myref.enclosing = encl_ref; 1831*5772Sas200622 myref.stream = encl_ref->stream; 1832*5772Sas200622 myref.packed_alignment = 0; 1833*5772Sas200622 myref.ti = type_under; 1834*5772Sas200622 myref.inner_flags = NDR_F_NONE; 1835*5772Sas200622 myref.name = name; 1836*5772Sas200622 1837*5772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 1838*5772Sas200622 (void) sprintf(name, "[%lu]", i); 1839*5772Sas200622 myref.pdu_offset = pdu_offset + i * size; 1840*5772Sas200622 valp = encl_ref->datum + i * size; 1841*5772Sas200622 myref.datum = valp; 1842*5772Sas200622 1843*5772Sas200622 if (!mlndr_inner(&myref)) 1844*5772Sas200622 return (0); 1845*5772Sas200622 1846*5772Sas200622 switch (size) { 1847*5772Sas200622 case 1: sense = *valp; break; 1848*5772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1849*5772Sas200622 case 2: sense = *(short *)valp; break; 1850*5772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1851*5772Sas200622 case 4: sense = *(long *)valp; break; 1852*5772Sas200622 } 1853*5772Sas200622 1854*5772Sas200622 if (!sense) 1855*5772Sas200622 break; 1856*5772Sas200622 } 1857*5772Sas200622 1858*5772Sas200622 return (1); 1859*5772Sas200622 } 1860*5772Sas200622 1861*5772Sas200622 1862*5772Sas200622 extern int mlndr_s_wchar(struct ndr_reference *encl_ref); 1863*5772Sas200622 struct ndr_typeinfo ndt_s_wchar = { 1864*5772Sas200622 1, /* NDR version */ 1865*5772Sas200622 2-1, /* alignment */ 1866*5772Sas200622 NDR_F_STRING, /* flags */ 1867*5772Sas200622 mlndr_s_wchar, /* ndr_func */ 1868*5772Sas200622 0, /* pdu_size_fixed_part */ 1869*5772Sas200622 2, /* pdu_size_variable_part */ 1870*5772Sas200622 0, /* c_size_fixed_part */ 1871*5772Sas200622 1, /* c_size_variable_part */ 1872*5772Sas200622 }; 1873*5772Sas200622 1874*5772Sas200622 1875*5772Sas200622 /* 1876*5772Sas200622 * Hand coded wchar function because all strings are transported 1877*5772Sas200622 * as wide characters. During NDR_M_OP_MARSHALL, we convert from 1878*5772Sas200622 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 1879*5772Sas200622 * convert from wide characters to multi-byte. 1880*5772Sas200622 * 1881*5772Sas200622 * It appeared that NT would sometimes leave a spurious character 1882*5772Sas200622 * in the data stream before the null wide_char, which would get 1883*5772Sas200622 * included in the string decode because we processed until the 1884*5772Sas200622 * null character. It now looks like NT does not always terminate 1885*5772Sas200622 * RPC Unicode strings and the terminating null is a side effect 1886*5772Sas200622 * of field alignment. So now we rely on the strlen_is (set up in 1887*5772Sas200622 * mlndr_outer_string) of the enclosing reference. This may or may 1888*5772Sas200622 * not include the null but it doesn't matter, the algorithm will 1889*5772Sas200622 * get it right. 1890*5772Sas200622 */ 1891*5772Sas200622 int 1892*5772Sas200622 mlndr_s_wchar(struct ndr_reference *encl_ref) 1893*5772Sas200622 { 1894*5772Sas200622 struct mlndr_stream *mlnds = encl_ref->stream; 1895*5772Sas200622 unsigned short wide_char; 1896*5772Sas200622 char *valp; 1897*5772Sas200622 struct ndr_reference myref; 1898*5772Sas200622 unsigned long i; 1899*5772Sas200622 char name[30]; 1900*5772Sas200622 int count; 1901*5772Sas200622 int char_count = 0; 1902*5772Sas200622 1903*5772Sas200622 if (mlnds->m_op == NDR_M_OP_UNMARSHALL) { 1904*5772Sas200622 /* 1905*5772Sas200622 * To avoid problems with zero length strings 1906*5772Sas200622 * we can just null terminate here and be done. 1907*5772Sas200622 */ 1908*5772Sas200622 if (encl_ref->strlen_is == 0) { 1909*5772Sas200622 encl_ref->datum[0] = '\0'; 1910*5772Sas200622 return (1); 1911*5772Sas200622 } 1912*5772Sas200622 } 1913*5772Sas200622 1914*5772Sas200622 bzero(&myref, sizeof (myref)); 1915*5772Sas200622 myref.enclosing = encl_ref; 1916*5772Sas200622 myref.stream = encl_ref->stream; 1917*5772Sas200622 myref.packed_alignment = 0; 1918*5772Sas200622 myref.ti = &ndt__wchar; 1919*5772Sas200622 myref.inner_flags = NDR_F_NONE; 1920*5772Sas200622 myref.datum = (char *)&wide_char; 1921*5772Sas200622 myref.name = name; 1922*5772Sas200622 myref.pdu_offset = encl_ref->pdu_offset; 1923*5772Sas200622 1924*5772Sas200622 valp = encl_ref->datum; 1925*5772Sas200622 count = 0; 1926*5772Sas200622 1927*5772Sas200622 for (i = 0; i < NDR_STRING_MAX; i++) { 1928*5772Sas200622 (void) sprintf(name, "[%lu]", i); 1929*5772Sas200622 1930*5772Sas200622 if (mlnds->m_op == NDR_M_OP_MARSHALL) { 1931*5772Sas200622 count = mts_mbtowc((mts_wchar_t *)&wide_char, valp, 1932*5772Sas200622 MTS_MB_CHAR_MAX); 1933*5772Sas200622 if (count < 0) { 1934*5772Sas200622 return (0); 1935*5772Sas200622 } else if (count == 0) { 1936*5772Sas200622 if (encl_ref->strlen_is != encl_ref->size_is) 1937*5772Sas200622 break; 1938*5772Sas200622 1939*5772Sas200622 /* 1940*5772Sas200622 * If the input char is 0, mbtowc 1941*5772Sas200622 * returns 0 without setting wide_char. 1942*5772Sas200622 * Set wide_char to 0 and a count of 1. 1943*5772Sas200622 */ 1944*5772Sas200622 wide_char = *valp; 1945*5772Sas200622 count = 1; 1946*5772Sas200622 } 1947*5772Sas200622 } 1948*5772Sas200622 1949*5772Sas200622 if (!mlndr_inner(&myref)) 1950*5772Sas200622 return (0); 1951*5772Sas200622 1952*5772Sas200622 if (mlnds->m_op == NDR_M_OP_UNMARSHALL) { 1953*5772Sas200622 count = mts_wctomb(valp, wide_char); 1954*5772Sas200622 1955*5772Sas200622 if ((++char_count) == encl_ref->strlen_is) { 1956*5772Sas200622 valp += count; 1957*5772Sas200622 *valp = '\0'; 1958*5772Sas200622 break; 1959*5772Sas200622 } 1960*5772Sas200622 } 1961*5772Sas200622 1962*5772Sas200622 if (!wide_char) 1963*5772Sas200622 break; 1964*5772Sas200622 1965*5772Sas200622 myref.pdu_offset += sizeof (wide_char); 1966*5772Sas200622 valp += count; 1967*5772Sas200622 } 1968*5772Sas200622 1969*5772Sas200622 return (1); 1970*5772Sas200622 } 1971*5772Sas200622 1972*5772Sas200622 /* 1973*5772Sas200622 * Converts a multibyte character string to a little-endian, wide-char 1974*5772Sas200622 * string. No more than nwchars wide characters are stored. 1975*5772Sas200622 * A terminating null wide character is appended if there is room. 1976*5772Sas200622 * 1977*5772Sas200622 * Returns the number of wide characters converted, not counting 1978*5772Sas200622 * any terminating null wide character. Returns -1 if an invalid 1979*5772Sas200622 * multibyte character is encountered. 1980*5772Sas200622 */ 1981*5772Sas200622 size_t 1982*5772Sas200622 ndr_mbstowcs(struct mlndr_stream *mlnds, mts_wchar_t *wcs, const char *mbs, 1983*5772Sas200622 size_t nwchars) 1984*5772Sas200622 { 1985*5772Sas200622 mts_wchar_t *start = wcs; 1986*5772Sas200622 int nbytes; 1987*5772Sas200622 1988*5772Sas200622 while (nwchars--) { 1989*5772Sas200622 nbytes = ndr_mbtowc(mlnds, wcs, mbs, MTS_MB_CHAR_MAX); 1990*5772Sas200622 if (nbytes < 0) { 1991*5772Sas200622 *wcs = 0; 1992*5772Sas200622 return ((size_t)-1); 1993*5772Sas200622 } 1994*5772Sas200622 1995*5772Sas200622 if (*mbs == 0) 1996*5772Sas200622 break; 1997*5772Sas200622 1998*5772Sas200622 ++wcs; 1999*5772Sas200622 mbs += nbytes; 2000*5772Sas200622 } 2001*5772Sas200622 2002*5772Sas200622 return (wcs - start); 2003*5772Sas200622 } 2004*5772Sas200622 2005*5772Sas200622 /* 2006*5772Sas200622 * Converts a multibyte character to a little-endian, wide-char, which 2007*5772Sas200622 * is stored in wcharp. Up to nbytes bytes are examined. 2008*5772Sas200622 * 2009*5772Sas200622 * If mbchar is valid, returns the number of bytes processed in mbchar. 2010*5772Sas200622 * If mbchar is invalid, returns -1. See also mts_mbtowc(). 2011*5772Sas200622 */ 2012*5772Sas200622 /*ARGSUSED*/ 2013*5772Sas200622 int 2014*5772Sas200622 ndr_mbtowc(struct mlndr_stream *mlnds, mts_wchar_t *wcharp, 2015*5772Sas200622 const char *mbchar, size_t nbytes) 2016*5772Sas200622 { 2017*5772Sas200622 int rc; 2018*5772Sas200622 2019*5772Sas200622 if ((rc = mts_mbtowc(wcharp, mbchar, nbytes)) < 0) 2020*5772Sas200622 return (rc); 2021*5772Sas200622 2022*5772Sas200622 #ifdef _BIG_ENDIAN 2023*5772Sas200622 if (mlnds == NULL || NDR_MODE_MATCH(mlnds, NDR_MODE_RETURN_SEND)) 2024*5772Sas200622 *wcharp = BSWAP_16(*wcharp); 2025*5772Sas200622 #endif 2026*5772Sas200622 2027*5772Sas200622 return (rc); 2028*5772Sas200622 } 2029