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 * Copyright 2012 Milan Jurik. All rights reserved. 25 */ 26 27 /* 28 * Network Data Representation (NDR) is a compatible subset of the DCE RPC 29 * and MSRPC NDR. NDR is used to move parameters consisting of 30 * complicated trees of data constructs between an RPC client and server. 31 */ 32 33 #include <sys/byteorder.h> 34 #include <strings.h> 35 #include <assert.h> 36 #include <string.h> 37 #include <stdlib.h> 38 39 #include <smbsrv/libsmb.h> 40 #include <smbsrv/string.h> 41 #include <smbsrv/libmlrpc.h> 42 43 #define NDR_STRING_MAX 4096 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 */ 1214 size_is = smb_wcequiv_strlen(valp) / 1215 sizeof (smb_wchar_t); 1216 1217 if (!(nds->flags & NDS_F_NONULL)) 1218 ++size_is; 1219 1220 if (size_is > NDR_STRING_MAX) { 1221 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1222 return (0); 1223 } 1224 } else { 1225 valp = outer_ref->datum; 1226 n_zeroes = 0; 1227 for (ix = 0; ix < NDR_STRING_MAX; ix++) { 1228 if (valp[ix] == 0) { 1229 n_zeroes++; 1230 if (n_zeroes >= is_varlen && 1231 ix % is_varlen == 0) { 1232 break; 1233 } 1234 } else { 1235 n_zeroes = 0; 1236 } 1237 } 1238 if (ix >= NDR_STRING_MAX) { 1239 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); 1240 return (0); 1241 } 1242 size_is = ix+1; 1243 } 1244 1245 first_is = 0; 1246 1247 if (nds->flags & NDS_F_NOTERM) 1248 length_is = size_is - 1; 1249 else 1250 length_is = size_is; 1251 1252 if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) || 1253 !ndr_outer_poke_sizing(outer_ref, 4, &first_is) || 1254 !ndr_outer_poke_sizing(outer_ref, 8, &length_is)) 1255 return (0); /* error already set */ 1256 break; 1257 1258 case NDR_M_OP_UNMARSHALL: 1259 if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) || 1260 !ndr_outer_peek_sizing(outer_ref, 4, &first_is) || 1261 !ndr_outer_peek_sizing(outer_ref, 8, &length_is)) 1262 return (0); /* error already set */ 1263 1264 /* 1265 * In addition to the first_is check, we used to check that 1266 * size_is or size_is-1 was equal to length_is but Windows95 1267 * doesn't conform to this "rule" (see variable part below). 1268 * The srvmgr tool for Windows95 sent the following values 1269 * for a path string: 1270 * 1271 * size_is = 261 (0x105) 1272 * first_is = 0 1273 * length_is = 53 (0x35) 1274 * 1275 * The length_is was correct (for the given path) but the 1276 * size_is was the maximum path length rather than being 1277 * related to length_is. 1278 */ 1279 if (first_is != 0) { 1280 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING); 1281 return (0); 1282 } 1283 1284 if (ti == &ndt_s_wchar) { 1285 /* 1286 * Decoding Unicode to UTF-8; we need to allow 1287 * for the maximum possible char size. It would 1288 * be nice to use mbequiv_strlen but the string 1289 * may not be null terminated. 1290 */ 1291 n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX; 1292 } else { 1293 n_alloc = (size_is + 1) * is_varlen; 1294 } 1295 1296 valp = NDS_MALLOC(nds, n_alloc, outer_ref); 1297 if (!valp) { 1298 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED); 1299 return (0); 1300 } 1301 1302 bzero(valp, (size_is+1) * is_varlen); 1303 1304 if (outer_ref->backptr) 1305 *outer_ref->backptr = valp; 1306 outer_ref->datum = valp; 1307 break; 1308 1309 default: 1310 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1311 return (0); 1312 } 1313 1314 /* 1315 * Variable part - exactly length_is of these. 1316 * 1317 * Usually, length_is is same as size_is and includes nul. 1318 * Some protocols use length_is = size_is-1, and length_is does 1319 * not include the nul (which is more consistent with DCE spec). 1320 * If the length_is is 0, there is no data following the 1321 * sizing header, regardless of size_is. 1322 */ 1323 n_variable = length_is * is_varlen; 1324 1325 /* sum them up to determine the PDU space required */ 1326 n_pdu_total = n_hdr + n_fixed + n_variable; 1327 1328 /* similar sum to determine how much local memory is required */ 1329 n_alloc = n_fixed + n_variable; 1330 1331 rc = ndr_outer_grow(outer_ref, n_pdu_total); 1332 if (!rc) 1333 return (rc); /* error already set */ 1334 1335 if (length_is > 0) { 1336 bzero(&myref, sizeof (myref)); 1337 myref.stream = nds; 1338 myref.enclosing = outer_ref; 1339 myref.ti = outer_ref->ti; 1340 myref.datum = outer_ref->datum; 1341 myref.name = "OUTER-STRING"; 1342 myref.outer_flags = NDR_F_IS_STRING; 1343 myref.inner_flags = NDR_F_NONE; 1344 1345 /* 1346 * Set up size_is and strlen_is for ndr_s_wchar. 1347 */ 1348 myref.size_is = size_is; 1349 myref.strlen_is = length_is; 1350 } 1351 1352 myref.pdu_offset = outer_ref->pdu_offset + 12; 1353 1354 /* 1355 * Don't try to decode empty strings. 1356 */ 1357 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) { 1358 nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1359 return (1); 1360 } 1361 1362 if ((size_is != 0) && (length_is != 0)) { 1363 rc = ndr_inner(&myref); 1364 if (!rc) 1365 return (rc); /* error already set */ 1366 } 1367 1368 nds->pdu_scan_offset = outer_ref->pdu_end_offset; 1369 return (1); 1370 } 1371 1372 int 1373 ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset, 1374 unsigned long *sizing_p) 1375 { 1376 ndr_stream_t *nds = outer_ref->stream; 1377 unsigned long pdu_offset; 1378 int rc; 1379 1380 pdu_offset = outer_ref->pdu_offset + offset; 1381 1382 if (pdu_offset < nds->outer_current->pdu_offset || 1383 pdu_offset > nds->outer_current->pdu_end_offset || 1384 pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1385 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1386 return (0); 1387 } 1388 1389 switch (nds->m_op) { 1390 case NDR_M_OP_MARSHALL: 1391 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1392 return (0); 1393 1394 case NDR_M_OP_UNMARSHALL: 1395 rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p, 1396 nds->swap, outer_ref); 1397 break; 1398 1399 default: 1400 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1401 return (0); 1402 } 1403 1404 return (rc); 1405 } 1406 1407 int 1408 ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset, 1409 unsigned long *sizing_p) 1410 { 1411 ndr_stream_t *nds = outer_ref->stream; 1412 unsigned long pdu_offset; 1413 int rc; 1414 1415 pdu_offset = outer_ref->pdu_offset + offset; 1416 1417 if (pdu_offset < nds->outer_current->pdu_offset || 1418 pdu_offset > nds->outer_current->pdu_end_offset || 1419 pdu_offset+4 > nds->outer_current->pdu_end_offset) { 1420 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK); 1421 return (0); 1422 } 1423 1424 switch (nds->m_op) { 1425 case NDR_M_OP_MARSHALL: 1426 rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p, 1427 nds->swap, outer_ref); 1428 break; 1429 1430 case NDR_M_OP_UNMARSHALL: 1431 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED); 1432 return (0); 1433 1434 default: 1435 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1436 return (0); 1437 } 1438 1439 return (rc); 1440 } 1441 1442 /* 1443 * All OUTER constructs begin on a mod4 (dword) boundary - except 1444 * for the ones that don't: some MSRPC calls appear to use word or 1445 * packed alignment. Strings appear to be dword aligned. 1446 */ 1447 int 1448 ndr_outer_align(ndr_ref_t *outer_ref) 1449 { 1450 ndr_stream_t *nds = outer_ref->stream; 1451 int rc; 1452 unsigned n_pad; 1453 unsigned align; 1454 1455 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) { 1456 align = outer_ref->ti->alignment; 1457 n_pad = ((align + 1) - nds->pdu_scan_offset) & align; 1458 } else { 1459 n_pad = NDR_ALIGN4(nds->pdu_scan_offset); 1460 } 1461 1462 if (n_pad == 0) 1463 return (1); /* already aligned, often the case */ 1464 1465 if (!ndr_outer_grow(outer_ref, n_pad)) 1466 return (0); /* error already set */ 1467 1468 switch (nds->m_op) { 1469 case NDR_M_OP_MARSHALL: 1470 rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref); 1471 if (!rc) { 1472 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED); 1473 return (0); 1474 } 1475 break; 1476 1477 case NDR_M_OP_UNMARSHALL: 1478 break; 1479 1480 default: 1481 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1482 return (0); 1483 } 1484 1485 nds->pdu_scan_offset += n_pad; 1486 return (1); 1487 } 1488 1489 int 1490 ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total) 1491 { 1492 ndr_stream_t *nds = outer_ref->stream; 1493 unsigned long pdu_want_size; 1494 int rc, is_ok = 0; 1495 1496 pdu_want_size = nds->pdu_scan_offset + n_total; 1497 1498 if (pdu_want_size <= nds->pdu_max_size) { 1499 is_ok = 1; 1500 } 1501 1502 switch (nds->m_op) { 1503 case NDR_M_OP_MARSHALL: 1504 if (is_ok) 1505 break; 1506 rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref); 1507 if (!rc) { 1508 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED); 1509 return (0); 1510 } 1511 break; 1512 1513 case NDR_M_OP_UNMARSHALL: 1514 if (is_ok) 1515 break; 1516 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW); 1517 return (0); 1518 1519 default: 1520 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID); 1521 return (0); 1522 } 1523 1524 if (nds->pdu_size < pdu_want_size) 1525 nds->pdu_size = pdu_want_size; 1526 1527 outer_ref->pdu_end_offset = pdu_want_size; 1528 return (1); 1529 } 1530 1531 /* 1532 * INNER ELEMENTS 1533 * 1534 * The local datum (arg_ref->datum) already exists, there is no need to 1535 * malloc() it. The datum should point at a member of a structure. 1536 * 1537 * For the most part, ndr_inner() and its helpers are just a sanity 1538 * check. The underlying ti->ndr_func() could be called immediately 1539 * for non-pointer elements. For the sake of robustness, we detect 1540 * run-time errors here. Most of the situations this protects against 1541 * have already been checked by the IDL compiler. This is also a 1542 * common point for processing of all data, and so is a convenient 1543 * place to work from for debugging. 1544 */ 1545 int 1546 ndr_inner(ndr_ref_t *arg_ref) 1547 { 1548 ndr_typeinfo_t *ti = arg_ref->ti; 1549 int is_varlen = ti->pdu_size_variable_part; 1550 int is_union = NDR_IS_UNION(ti); 1551 int error = NDR_ERR_INNER_PARAMS_BAD; 1552 int params; 1553 1554 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1555 1556 switch (params) { 1557 case NDR_F_NONE: 1558 if (is_union) { 1559 error = NDR_ERR_SWITCH_VALUE_MISSING; 1560 break; 1561 } 1562 return (*ti->ndr_func)(arg_ref); 1563 1564 case NDR_F_SIZE_IS: 1565 case NDR_F_DIMENSION_IS: 1566 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */ 1567 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */ 1568 if (is_varlen) { 1569 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL; 1570 break; 1571 } 1572 if (is_union) { 1573 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1574 break; 1575 } 1576 if (params & NDR_F_IS_POINTER) 1577 return (ndr_inner_pointer(arg_ref)); 1578 else if (params & NDR_F_IS_REFERENCE) 1579 return (ndr_inner_reference(arg_ref)); 1580 else 1581 return (ndr_inner_array(arg_ref)); 1582 1583 case NDR_F_IS_POINTER: /* type is pointer to one something */ 1584 if (is_union) { 1585 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1586 break; 1587 } 1588 return (ndr_inner_pointer(arg_ref)); 1589 1590 case NDR_F_IS_REFERENCE: /* type is pointer to one something */ 1591 if (is_union) { 1592 error = NDR_ERR_ARRAY_UNION_ILLEGAL; 1593 break; 1594 } 1595 return (ndr_inner_reference(arg_ref)); 1596 1597 case NDR_F_SWITCH_IS: 1598 if (!is_union) { 1599 error = NDR_ERR_SWITCH_VALUE_ILLEGAL; 1600 break; 1601 } 1602 return (*ti->ndr_func)(arg_ref); 1603 1604 default: 1605 error = NDR_ERR_INNER_PARAMS_BAD; 1606 break; 1607 } 1608 1609 /* 1610 * If we get here, something is wrong. Most likely, 1611 * the params flags do not match 1612 */ 1613 NDR_SET_ERROR(arg_ref, error); 1614 return (0); 1615 } 1616 1617 int 1618 ndr_inner_pointer(ndr_ref_t *arg_ref) 1619 { 1620 ndr_stream_t *nds = arg_ref->stream; 1621 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1622 char **valpp = (char **)arg_ref->datum; 1623 ndr_ref_t *outer_ref; 1624 1625 if (!ndr__ulong(arg_ref)) 1626 return (0); /* error */ 1627 if (!*valpp) 1628 return (1); /* NULL pointer */ 1629 1630 outer_ref = ndr_enter_outer_queue(arg_ref); 1631 if (!outer_ref) 1632 return (0); /* error already set */ 1633 1634 /* 1635 * Move advice in inner_flags to outer_flags. 1636 * Retain pointer flag for conformant arrays. 1637 */ 1638 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1639 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1640 outer_ref->outer_flags &= ~NDR_F_IS_POINTER; 1641 #ifdef NDR_INNER_PTR_NOT_YET 1642 outer_ref->outer_flags |= NDR_F_BACKPTR; 1643 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1644 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1645 } 1646 #endif /* NDR_INNER_PTR_NOT_YET */ 1647 1648 outer_ref->backptr = valpp; 1649 1650 switch (nds->m_op) { 1651 case NDR_M_OP_MARSHALL: 1652 outer_ref->datum = *valpp; 1653 break; 1654 1655 case NDR_M_OP_UNMARSHALL: 1656 /* 1657 * This is probably wrong if the application allocated 1658 * memory in advance. Indicate no value for now. 1659 * ONC RPC handles this case. 1660 */ 1661 *valpp = 0; 1662 outer_ref->datum = 0; 1663 break; 1664 } 1665 1666 return (1); /* pointer dereference scheduled */ 1667 } 1668 1669 int 1670 ndr_inner_reference(ndr_ref_t *arg_ref) 1671 { 1672 ndr_stream_t *nds = arg_ref->stream; 1673 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1674 char **valpp = (char **)arg_ref->datum; 1675 ndr_ref_t *outer_ref; 1676 1677 outer_ref = ndr_enter_outer_queue(arg_ref); 1678 if (!outer_ref) 1679 return (0); /* error already set */ 1680 1681 /* 1682 * Move advice in inner_flags to outer_flags. 1683 * Retain reference flag for conformant arrays. 1684 */ 1685 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK; 1686 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0) 1687 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE; 1688 #ifdef NDR_INNER_REF_NOT_YET 1689 outer_ref->outer_flags |= NDR_F_BACKPTR; 1690 if (outer_ref->outer_flags & NDR_F_SIZE_IS) { 1691 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT; 1692 } 1693 #endif /* NDR_INNER_REF_NOT_YET */ 1694 1695 outer_ref->backptr = valpp; 1696 1697 switch (nds->m_op) { 1698 case NDR_M_OP_MARSHALL: 1699 outer_ref->datum = *valpp; 1700 break; 1701 1702 case NDR_M_OP_UNMARSHALL: 1703 /* 1704 * This is probably wrong if the application allocated 1705 * memory in advance. Indicate no value for now. 1706 * ONC RPC handles this case. 1707 */ 1708 *valpp = 0; 1709 outer_ref->datum = 0; 1710 break; 1711 } 1712 1713 return (1); /* pointer dereference scheduled */ 1714 } 1715 1716 int 1717 ndr_inner_array(ndr_ref_t *encl_ref) 1718 { 1719 ndr_typeinfo_t *ti = encl_ref->ti; 1720 ndr_ref_t myref; 1721 unsigned long pdu_offset = encl_ref->pdu_offset; 1722 unsigned long n_elem; 1723 unsigned long i; 1724 char name[30]; 1725 1726 if (encl_ref->inner_flags & NDR_F_SIZE_IS) { 1727 /* now is the time to check/set size */ 1728 if (!ndr_size_is(encl_ref)) 1729 return (0); /* error already set */ 1730 n_elem = encl_ref->size_is; 1731 } else { 1732 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS); 1733 n_elem = encl_ref->dimension_is; 1734 } 1735 1736 bzero(&myref, sizeof (myref)); 1737 myref.enclosing = encl_ref; 1738 myref.stream = encl_ref->stream; 1739 myref.packed_alignment = 0; 1740 myref.ti = ti; 1741 myref.inner_flags = NDR_F_NONE; 1742 1743 for (i = 0; i < n_elem; i++) { 1744 (void) sprintf(name, "[%lu]", i); 1745 myref.name = name; 1746 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part; 1747 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part; 1748 1749 if (!ndr_inner(&myref)) 1750 return (0); 1751 } 1752 1753 return (1); 1754 } 1755 1756 1757 /* 1758 * BASIC TYPES 1759 */ 1760 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1761 extern int ndr_##TYPE(struct ndr_reference *encl_ref); \ 1762 ndr_typeinfo_t ndt_##TYPE = { \ 1763 1, /* NDR version */ \ 1764 (SIZE)-1, /* alignment */ \ 1765 NDR_F_NONE, /* flags */ \ 1766 ndr_##TYPE, /* ndr_func */ \ 1767 SIZE, /* pdu_size_fixed_part */ \ 1768 0, /* pdu_size_variable_part */ \ 1769 SIZE, /* c_size_fixed_part */ \ 1770 0, /* c_size_variable_part */ \ 1771 }; \ 1772 int ndr_##TYPE(struct ndr_reference *ref) { \ 1773 return (ndr_basic_integer(ref, SIZE)); \ 1774 } 1775 1776 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \ 1777 extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \ 1778 ndr_typeinfo_t ndt_s##TYPE = { \ 1779 1, /* NDR version */ \ 1780 (SIZE)-1, /* alignment */ \ 1781 NDR_F_STRING, /* flags */ \ 1782 ndr_s##TYPE, /* ndr_func */ \ 1783 0, /* pdu_size_fixed_part */ \ 1784 SIZE, /* pdu_size_variable_part */ \ 1785 0, /* c_size_fixed_part */ \ 1786 SIZE, /* c_size_variable_part */ \ 1787 }; \ 1788 int ndr_s##TYPE(struct ndr_reference *ref) { \ 1789 return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \ 1790 } 1791 1792 #define MAKE_BASIC_TYPE(TYPE, SIZE) \ 1793 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \ 1794 MAKE_BASIC_TYPE_STRING(TYPE, SIZE) 1795 1796 int ndr_basic_integer(ndr_ref_t *, unsigned); 1797 int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *); 1798 1799 1800 MAKE_BASIC_TYPE(_char, 1) 1801 MAKE_BASIC_TYPE(_uchar, 1) 1802 MAKE_BASIC_TYPE(_short, 2) 1803 MAKE_BASIC_TYPE(_ushort, 2) 1804 MAKE_BASIC_TYPE(_long, 4) 1805 MAKE_BASIC_TYPE(_ulong, 4) 1806 1807 MAKE_BASIC_TYPE_BASE(_wchar, 2) 1808 1809 int 1810 ndr_basic_integer(ndr_ref_t *ref, unsigned size) 1811 { 1812 ndr_stream_t *nds = ref->stream; 1813 char *valp = (char *)ref->datum; 1814 int rc; 1815 1816 switch (nds->m_op) { 1817 case NDR_M_OP_MARSHALL: 1818 rc = NDS_PUT_PDU(nds, ref->pdu_offset, size, 1819 valp, nds->swap, ref); 1820 break; 1821 1822 case NDR_M_OP_UNMARSHALL: 1823 rc = NDS_GET_PDU(nds, ref->pdu_offset, size, 1824 valp, nds->swap, ref); 1825 break; 1826 1827 default: 1828 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID); 1829 return (0); 1830 } 1831 1832 return (rc); 1833 } 1834 1835 int 1836 ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under) 1837 { 1838 unsigned long pdu_offset = encl_ref->pdu_offset; 1839 unsigned size = type_under->pdu_size_fixed_part; 1840 char *valp; 1841 ndr_ref_t myref; 1842 unsigned long i; 1843 long sense = 0; 1844 char name[30]; 1845 1846 assert(size != 0); 1847 1848 bzero(&myref, sizeof (myref)); 1849 myref.enclosing = encl_ref; 1850 myref.stream = encl_ref->stream; 1851 myref.packed_alignment = 0; 1852 myref.ti = type_under; 1853 myref.inner_flags = NDR_F_NONE; 1854 myref.name = name; 1855 1856 for (i = 0; i < NDR_STRING_MAX; i++) { 1857 (void) sprintf(name, "[%lu]", i); 1858 myref.pdu_offset = pdu_offset + i * size; 1859 valp = encl_ref->datum + i * size; 1860 myref.datum = valp; 1861 1862 if (!ndr_inner(&myref)) 1863 return (0); 1864 1865 switch (size) { 1866 case 1: sense = *valp; break; 1867 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1868 case 2: sense = *(short *)valp; break; 1869 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1870 case 4: sense = *(long *)valp; break; 1871 } 1872 1873 if (!sense) 1874 break; 1875 } 1876 1877 return (1); 1878 } 1879 1880 1881 extern int ndr_s_wchar(ndr_ref_t *encl_ref); 1882 ndr_typeinfo_t ndt_s_wchar = { 1883 1, /* NDR version */ 1884 2-1, /* alignment */ 1885 NDR_F_STRING, /* flags */ 1886 ndr_s_wchar, /* ndr_func */ 1887 0, /* pdu_size_fixed_part */ 1888 2, /* pdu_size_variable_part */ 1889 0, /* c_size_fixed_part */ 1890 1, /* c_size_variable_part */ 1891 }; 1892 1893 1894 /* 1895 * Hand coded wchar function because all strings are transported 1896 * as wide characters. During NDR_M_OP_MARSHALL, we convert from 1897 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we 1898 * convert from wide characters to multi-byte. 1899 * 1900 * It appeared that NT would sometimes leave a spurious character 1901 * in the data stream before the null wide_char, which would get 1902 * included in the string decode because we processed until the 1903 * null character. It now looks like NT does not always terminate 1904 * RPC Unicode strings and the terminating null is a side effect 1905 * of field alignment. So now we rely on the strlen_is (set up in 1906 * ndr_outer_string) of the enclosing reference. This may or may 1907 * not include the null but it doesn't matter, the algorithm will 1908 * get it right. 1909 */ 1910 int 1911 ndr_s_wchar(ndr_ref_t *encl_ref) 1912 { 1913 ndr_stream_t *nds = encl_ref->stream; 1914 unsigned short wide_char; 1915 char *valp; 1916 ndr_ref_t myref; 1917 unsigned long i; 1918 char name[30]; 1919 int count; 1920 int char_count = 0; 1921 1922 if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1923 /* 1924 * To avoid problems with zero length strings 1925 * we can just null terminate here and be done. 1926 */ 1927 if (encl_ref->strlen_is == 0) { 1928 encl_ref->datum[0] = '\0'; 1929 return (1); 1930 } 1931 } 1932 1933 bzero(&myref, sizeof (myref)); 1934 myref.enclosing = encl_ref; 1935 myref.stream = encl_ref->stream; 1936 myref.packed_alignment = 0; 1937 myref.ti = &ndt__wchar; 1938 myref.inner_flags = NDR_F_NONE; 1939 myref.datum = (char *)&wide_char; 1940 myref.name = name; 1941 myref.pdu_offset = encl_ref->pdu_offset; 1942 1943 valp = encl_ref->datum; 1944 count = 0; 1945 1946 for (i = 0; i < NDR_STRING_MAX; i++) { 1947 (void) sprintf(name, "[%lu]", i); 1948 1949 if (nds->m_op == NDR_M_OP_MARSHALL) { 1950 count = smb_mbtowc((smb_wchar_t *)&wide_char, valp, 1951 MTS_MB_CHAR_MAX); 1952 if (count < 0) { 1953 return (0); 1954 } else if (count == 0) { 1955 if (encl_ref->strlen_is != encl_ref->size_is) 1956 break; 1957 1958 /* 1959 * If the input char is 0, mbtowc 1960 * returns 0 without setting wide_char. 1961 * Set wide_char to 0 and a count of 1. 1962 */ 1963 wide_char = *valp; 1964 count = 1; 1965 } 1966 } 1967 1968 if (!ndr_inner(&myref)) 1969 return (0); 1970 1971 if (nds->m_op == NDR_M_OP_UNMARSHALL) { 1972 count = smb_wctomb(valp, wide_char); 1973 1974 if ((++char_count) == encl_ref->strlen_is) { 1975 valp += count; 1976 *valp = '\0'; 1977 break; 1978 } 1979 } 1980 1981 if (!wide_char) 1982 break; 1983 1984 myref.pdu_offset += sizeof (wide_char); 1985 valp += count; 1986 } 1987 1988 return (1); 1989 } 1990 1991 /* 1992 * Converts a multibyte character string to a little-endian, wide-char 1993 * string. No more than nwchars wide characters are stored. 1994 * A terminating null wide character is appended if there is room. 1995 * 1996 * Returns the number of wide characters converted, not counting 1997 * any terminating null wide character. Returns -1 if an invalid 1998 * multibyte character is encountered. 1999 */ 2000 size_t 2001 ndr_mbstowcs(ndr_stream_t *nds, smb_wchar_t *wcs, const char *mbs, 2002 size_t nwchars) 2003 { 2004 smb_wchar_t *start = wcs; 2005 int nbytes; 2006 2007 while (nwchars--) { 2008 nbytes = ndr_mbtowc(nds, wcs, mbs, MTS_MB_CHAR_MAX); 2009 if (nbytes < 0) { 2010 *wcs = 0; 2011 return ((size_t)-1); 2012 } 2013 2014 if (*mbs == 0) 2015 break; 2016 2017 ++wcs; 2018 mbs += nbytes; 2019 } 2020 2021 return (wcs - start); 2022 } 2023 2024 /* 2025 * Converts a multibyte character to a little-endian, wide-char, which 2026 * is stored in wcharp. Up to nbytes bytes are examined. 2027 * 2028 * If mbchar is valid, returns the number of bytes processed in mbchar. 2029 * If mbchar is invalid, returns -1. See also smb_mbtowc(). 2030 */ 2031 /*ARGSUSED*/ 2032 int 2033 ndr_mbtowc(ndr_stream_t *nds, smb_wchar_t *wcharp, const char *mbchar, 2034 size_t nbytes) 2035 { 2036 int rc; 2037 2038 if ((rc = smb_mbtowc(wcharp, mbchar, nbytes)) < 0) 2039 return (rc); 2040 2041 #ifdef _BIG_ENDIAN 2042 if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) 2043 *wcharp = BSWAP_16(*wcharp); 2044 #endif 2045 2046 return (rc); 2047 }