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