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
ndo_process(ndr_stream_t * nds,ndr_typeinfo_t * ti,char * datum)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
ndo_operation(ndr_stream_t * nds,ndr_typeinfo_t * ti,int opnum,char * datum)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
ndr_params(ndr_ref_t * params_ref)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
ndr_topmost(ndr_ref_t * top_ref)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 *
ndr_enter_outer_queue(ndr_ref_t * arg_ref)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
ndr_run_outer_queue(ndr_stream_t * nds)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
ndr_outer(ndr_ref_t * outer_ref)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
ndr_outer_fixed(ndr_ref_t * outer_ref)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
ndr_outer_fixed_array(ndr_ref_t * outer_ref)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
ndr_outer_conformant_array(ndr_ref_t * outer_ref)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
ndr_outer_conformant_construct(ndr_ref_t * outer_ref)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
ndr_size_is(ndr_ref_t * ref)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
ndr_outer_string(ndr_ref_t * outer_ref)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
ndr_outer_peek_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)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
ndr_outer_poke_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)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
ndr_outer_align(ndr_ref_t * outer_ref)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
ndr_outer_grow(ndr_ref_t * outer_ref,unsigned n_total)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
ndr_inner(ndr_ref_t * arg_ref)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
ndr_inner_pointer(ndr_ref_t * arg_ref)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
ndr_inner_reference(ndr_ref_t * arg_ref)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
ndr_inner_array(ndr_ref_t * encl_ref)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
ndr_basic_integer(ndr_ref_t * ref,unsigned size)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
ndr_string_basic_integer(ndr_ref_t * encl_ref,ndr_typeinfo_t * type_under)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
ndr_s_wchar(ndr_ref_t * encl_ref)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
ndr_mbstowcs(ndr_stream_t * nds,smb_wchar_t * wcs,const char * mbs,size_t nwchars)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
ndr_mbtowc(ndr_stream_t * nds,smb_wchar_t * wcharp,const char * mbchar,size_t nbytes)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