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