1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
27 */
28
29 /*
30 * Network Data Representation (NDR) is a compatible subset of the DCE RPC
31 * and MSRPC NDR. NDR is used to move parameters consisting of
32 * complicated trees of data constructs between an RPC client and server.
33 */
34
35 #include <sys/byteorder.h>
36 #include <strings.h>
37 #include <assert.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 #include <libmlrpc.h>
43 #include <ndr_wchar.h>
44
45 #define NDR_IS_UNION(T) \
46 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
47 #define NDR_IS_STRING(T) \
48 (((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
49
50 extern ndr_typeinfo_t ndt_s_wchar;
51
52 /*
53 * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
54 *
55 * Each parameter (call arguments and return values) is a TOP-MOST item.
56 * A TOP-MOST item consists of one or more OUTER items. An OUTER item
57 * consists of one or more INNER items. There are important differences
58 * between each kind, which, primarily, have to do with the allocation
59 * of memory to contain data structures and the order of processing.
60 *
61 * This is most easily demonstrated with a short example.
62 * Consider these structures:
63 *
64 * struct top_param {
65 * long level;
66 * struct list * head;
67 * long count;
68 * };
69 *
70 * struct list {
71 * struct list * next;
72 * char * str; // a string
73 * };
74 *
75 * Now, consider an instance tree like this:
76 *
77 * +---------+ +-------+ +-------+
78 * |top_param| +--->|list #1| +--->|list #2|
79 * +---------+ | +-------+ | +-------+
80 * | level | | | next ----+ | next --->(NULL)
81 * | head ----+ | str -->"foo" | str -->"bar"
82 * | count | | flag | | flag |
83 * +---------+ +-------+ +-------+
84 *
85 * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
86 * The vertical bars (|) indicate OUTER construct boundaries.
87 *
88 * +-----+----------------------+----------------------+-----+-----+-----+
89 * |level|#1.next #1.str #1.flag|#2.next #2.str #2.flag|"bar"|"foo"|count|
90 * +-----+----------------------+----------------------+-----+-----+-----+
91 * level |<----------------------- head -------------------------->|count
92 * TOP TOP TOP
93 *
94 * Here's what to notice:
95 *
96 * - The members of the TOP-MOST construct are scattered through the Stub
97 * Data in the order they occur. This example shows a TOP-MOST construct
98 * consisting of atomic types (pointers and integers). A construct
99 * (struct) within the TOP-MOST construct would be contiguous and not
100 * scattered.
101 *
102 * - The members of OUTER constructs are contiguous, which allows for
103 * non-copied relocated (fixed-up) data structures at the packet's
104 * destination. We don't do fix-ups here. The pointers within the
105 * OUTER constructs are processed depth-first in the order that they
106 * occur. If they were processed breadth first, the sequence would
107 * be #1,"foo",#2,"bar". This is tricky because OUTER constructs may
108 * be variable length, and pointers are often encountered before the
109 * size(s) is known.
110 *
111 * - The INNER constructs are simply the members of an OUTER construct.
112 *
113 * For comparison, consider how ONC RPC would handle the same tree of
114 * data. ONC requires very little buffering, while DCE requires enough
115 * buffer space for the entire message. ONC does atom-by-atom depth-first
116 * (de)serialization and copy, while DCE allows for constructs to be
117 * "fixed-up" (relocated) in place at the destination. The packet data
118 * for the same tree processed by ONC RPC would look like this:
119 *
120 * +---------------------------------------------------------------------+
121 * |level #1.next #2.next #2.str "bar" #2.flag #1.str "foo" #1.flag count|
122 * +---------------------------------------------------------------------+
123 * TOP #1 #2 #2 bar #2 #1 foo #1 TOP
124 *
125 * More details about each TOP-MOST, OUTER, and INNER constructs appear
126 * throughout this source file near where such constructs are processed.
127 *
128 * NDR_REFERENCE
129 *
130 * The primary object for NDR is the ndr_ref_t.
131 *
132 * An ndr reference indicates the local datum (i.e. native "C" data
133 * format), and the element within the Stub Data (contained within the
134 * RPC PDU (protocol data unit). An ndr reference also indicates,
135 * largely as a debugging aid, something about the type of the
136 * element/datum, and the enclosing construct for the element. The
137 * ndr reference's are typically allocated on the stack as locals,
138 * and the chain of ndr-reference.enclosing references is in reverse
139 * order of the call graph.
140 *
141 * The ndr-reference.datum is a pointer to the local memory that
142 * contains/receives the value. The ndr-reference.pdu_offset indicates
143 * where in the Stub Data the value is to be stored/retrieved.
144 *
145 * The ndr-reference also contains various parameters to the NDR
146 * process, such as ndr-reference.size_is, which indicates the size
147 * of variable length data, or ndr-reference.switch_is, which
148 * indicates the arm of a union to use.
149 *
150 * QUEUE OF OUTER REFERENCES
151 *
152 * Some OUTER constructs are variable size. Sometimes (often) we don't
153 * know the size of the OUTER construct until after pointers have been
154 * encountered. Hence, we can not begin processing the referent of the
155 * pointer until after the referring OUTER construct is completely
156 * processed, i.e. we don't know where to find/put the referent in the
157 * Stub Data until we know the size of all its predecessors.
158 *
159 * This is managed using the queue of OUTER references. The queue is
160 * anchored in ndr_stream.outer_queue_head. At any time,
161 * ndr_stream.outer_queue_tailp indicates where to put the
162 * ndr-reference for the next encountered pointer.
163 *
164 * Refer to the example above as we illustrate the queue here. In these
165 * illustrations, the queue entries are not the data structures themselves.
166 * Rather, they are ndr-reference entries which **refer** to the data
167 * structures in both the PDU and local memory.
168 *
169 * During some point in the processing, the queue looks like this:
170 *
171 * outer_current -------v
172 * outer_queue_head --> list#1 --0
173 * outer_queue_tailp ---------&
174 *
175 * When the pointer #1.next is encountered, and entry is added to the
176 * queue,
177 *
178 * outer_current -------v
179 * outer_queue_head --> list#1 --> list#2 --0
180 * outer_queue_tailp --------------------&
181 *
182 * and the members of #1 continue to be processed, which encounters
183 * #1.str:
184 *
185 * outer_current -------v
186 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
187 * outer_queue_tailp ------------------------------&
188 *
189 * Upon the completion of list#1, the processing continues by moving to
190 * ndr_stream.outer_current->next, and the tail is set to this outer member:
191 *
192 * outer_current ------------------v
193 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
194 * outer_queue_tailp --------------------&
195 *
196 * Space for list#2 is allocated, either in the Stub Data or of local
197 * memory. When #2.next is encountered, it is found to be the null
198 * pointer and no reference is added to the queue. When #2.str is
199 * encountered, it is found to be valid, and a reference is added:
200 *
201 * outer_current ------------------v
202 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
203 * outer_queue_tailp ------------------------------&
204 *
205 * Processing continues in a similar fashion with the string "bar",
206 * which is variable-length. At this point, memory for "bar" may be
207 * malloc()ed during NDR_M_OP_UNMARSHALL:
208 *
209 * outer_current -----------------------------v
210 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
211 * outer_queue_tailp ------------------------------&
212 *
213 * And finishes on string "foo". Notice that because "bar" is a
214 * variable length string, and we don't know the PDU offset for "foo"
215 * until we reach this point.
216 *
217 * When the queue is drained (current->next==0), processing continues
218 * with the next TOP-MOST member.
219 *
220 * The queue of OUTER constructs manages the variable-length semantics
221 * of OUTER constructs and satisfies the depth-first requirement.
222 * We allow the queue to linger until the entire TOP-MOST structure is
223 * processed as an aid to debugging.
224 */
225
226 static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
227 extern int ndr__ulong(ndr_ref_t *);
228
229 /*
230 * TOP-MOST ELEMENTS
231 *
232 * This is fundamentally the first OUTER construct of the parameter,
233 * possibly followed by more OUTER constructs due to pointers. The
234 * datum (local memory) for TOP-MOST constructs (structs) is allocated
235 * by the caller of NDR.
236 *
237 * After the element is transferred, the outer_queue is drained.
238 *
239 * All we have to do is add an entry to the outer_queue for this
240 * top-most member, and commence the outer_queue processing.
241 */
242 int
ndo_process(ndr_stream_t * nds,ndr_typeinfo_t * ti,char * datum)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
ndo_operation(ndr_stream_t * nds,ndr_typeinfo_t * ti,int opnum,char * datum)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
ndr_params(ndr_ref_t * params_ref)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
ndr_topmost(ndr_ref_t * top_ref)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 *
ndr_enter_outer_queue(ndr_ref_t * arg_ref)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
ndr_run_outer_queue(ndr_stream_t * nds)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
ndr_outer(ndr_ref_t * outer_ref)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
ndr_outer_fixed(ndr_ref_t * outer_ref)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
ndr_outer_fixed_array(ndr_ref_t * outer_ref)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
ndr_outer_conformant_array(ndr_ref_t * outer_ref)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
ndr_outer_conformant_construct(ndr_ref_t * outer_ref)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
ndr_size_is(ndr_ref_t * ref)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
ndr_outer_string(ndr_ref_t * outer_ref)1162 ndr_outer_string(ndr_ref_t *outer_ref)
1163 {
1164 ndr_stream_t *nds = outer_ref->stream;
1165 ndr_typeinfo_t *ti = outer_ref->ti;
1166 ndr_ref_t myref;
1167 char *valp = NULL;
1168 unsigned is_varlen = ti->pdu_size_variable_part;
1169 int is_union = NDR_IS_UNION(ti);
1170 int is_string = NDR_IS_STRING(ti);
1171 int rc;
1172 unsigned n_zeroes;
1173 unsigned ix;
1174 unsigned long size_is;
1175 unsigned long first_is;
1176 unsigned long length_is;
1177 unsigned n_hdr;
1178 unsigned n_fixed;
1179 unsigned n_variable;
1180 unsigned n_alloc;
1181 unsigned n_pdu_total;
1182 int params;
1183
1184 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1185
1186 assert(is_varlen && is_string && !is_union);
1187 assert(params == NDR_F_NONE);
1188
1189 /* string header for this: size_is first_is length_is */
1190 n_hdr = 12;
1191
1192 /* fixed part -- exactly none of these */
1193 n_fixed = 0;
1194
1195 if (!ndr_outer_grow(outer_ref, n_hdr))
1196 return (0); /* error already set */
1197
1198 switch (nds->m_op) {
1199 case NDR_M_OP_MARSHALL:
1200 valp = outer_ref->datum;
1201 if (!valp) {
1202 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
1203 return (0);
1204 }
1205
1206 if (outer_ref->backptr)
1207 assert(valp == *outer_ref->backptr);
1208
1209 if (ti == &ndt_s_wchar) {
1210 /*
1211 * size_is is the number of characters in the
1212 * (multibyte) string, including the null.
1213 * In other words, symbols, not bytes.
1214 */
1215 size_t wlen;
1216 wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
1217 if (wlen == (size_t)-1) {
1218 /* illegal sequence error? */
1219 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1220 return (0);
1221 }
1222 if ((nds->flags & NDS_F_NONULL) == 0)
1223 wlen++;
1224 if (wlen > NDR_STRING_MAX) {
1225 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1226 return (0);
1227 }
1228 size_is = wlen;
1229 } else {
1230 valp = outer_ref->datum;
1231 n_zeroes = 0;
1232 for (ix = 0; ix < NDR_STRING_MAX; ix++) {
1233 if (valp[ix] == 0) {
1234 n_zeroes++;
1235 if (n_zeroes >= is_varlen &&
1236 ix % is_varlen == 0) {
1237 break;
1238 }
1239 } else {
1240 n_zeroes = 0;
1241 }
1242 }
1243 if (ix >= NDR_STRING_MAX) {
1244 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1245 return (0);
1246 }
1247 size_is = ix+1;
1248 }
1249
1250 first_is = 0;
1251
1252 if (nds->flags & NDS_F_NOTERM)
1253 length_is = size_is - 1;
1254 else
1255 length_is = size_is;
1256
1257 if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
1258 !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
1259 !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
1260 return (0); /* error already set */
1261 break;
1262
1263 case NDR_M_OP_UNMARSHALL:
1264 if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
1265 !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
1266 !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
1267 return (0); /* error already set */
1268
1269 /*
1270 * Enforce bounds on: size_is, first_is, length_is
1271 *
1272 * In addition to the first_is check, we used to check that
1273 * size_is or size_is-1 was equal to length_is but Windows95
1274 * doesn't conform to this "rule" (see variable part below).
1275 * The srvmgr tool for Windows95 sent the following values
1276 * for a path string:
1277 *
1278 * size_is = 261 (0x105)
1279 * first_is = 0
1280 * length_is = 53 (0x35)
1281 *
1282 * The length_is was correct (for the given path) but the
1283 * size_is was the maximum path length rather than being
1284 * related to length_is.
1285 */
1286 if (size_is > NDR_STRING_MAX) {
1287 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1288 return (0);
1289 }
1290 if (first_is != 0) {
1291 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1292 return (0);
1293 }
1294 if (length_is > size_is) {
1295 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1296 return (0);
1297 }
1298
1299 if (ti == &ndt_s_wchar) {
1300 /*
1301 * Decoding Unicode to UTF-8; we need to allow
1302 * for the maximum possible char size. It would
1303 * be nice to use mbequiv_strlen but the string
1304 * may not be null terminated.
1305 */
1306 n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
1307 } else {
1308 n_alloc = (size_is + 1) * is_varlen;
1309 }
1310
1311 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1312 if (!valp) {
1313 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1314 return (0);
1315 }
1316
1317 bzero(valp, (size_is+1) * is_varlen);
1318
1319 if (outer_ref->backptr)
1320 *outer_ref->backptr = valp;
1321 outer_ref->datum = valp;
1322 break;
1323
1324 default:
1325 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1326 return (0);
1327 }
1328
1329 /*
1330 * Variable part - exactly length_is of these.
1331 *
1332 * Usually, length_is is same as size_is and includes nul.
1333 * Some protocols use length_is = size_is-1, and length_is does
1334 * not include the nul (which is more consistent with DCE spec).
1335 * If the length_is is 0, there is no data following the
1336 * sizing header, regardless of size_is.
1337 */
1338 n_variable = length_is * is_varlen;
1339
1340 /* sum them up to determine the PDU space required */
1341 n_pdu_total = n_hdr + n_fixed + n_variable;
1342
1343 /* similar sum to determine how much local memory is required */
1344 n_alloc = n_fixed + n_variable;
1345
1346 rc = ndr_outer_grow(outer_ref, n_pdu_total);
1347 if (!rc)
1348 return (rc); /* error already set */
1349
1350 if (length_is > 0) {
1351 bzero(&myref, sizeof (myref));
1352 myref.stream = nds;
1353 myref.enclosing = outer_ref;
1354 myref.ti = outer_ref->ti;
1355 myref.datum = outer_ref->datum;
1356 myref.name = "OUTER-STRING";
1357 myref.outer_flags = NDR_F_IS_STRING;
1358 myref.inner_flags = NDR_F_NONE;
1359
1360 /*
1361 * Set up size_is and strlen_is for ndr_s_wchar.
1362 */
1363 myref.size_is = size_is;
1364 myref.strlen_is = length_is;
1365 }
1366
1367 myref.pdu_offset = outer_ref->pdu_offset + 12;
1368
1369 /*
1370 * Don't try to decode empty strings.
1371 */
1372 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
1373 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1374 return (1);
1375 }
1376
1377 if ((size_is != 0) && (length_is != 0)) {
1378 rc = ndr_inner(&myref);
1379 if (!rc)
1380 return (rc); /* error already set */
1381 }
1382
1383 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1384 return (1);
1385 }
1386
1387 int
ndr_outer_peek_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)1388 ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
1389 unsigned long *sizing_p)
1390 {
1391 ndr_stream_t *nds = outer_ref->stream;
1392 unsigned long pdu_offset;
1393 int rc;
1394
1395 pdu_offset = outer_ref->pdu_offset + offset;
1396
1397 if (pdu_offset < nds->outer_current->pdu_offset ||
1398 pdu_offset > nds->outer_current->pdu_end_offset ||
1399 pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1400 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1401 return (0);
1402 }
1403
1404 switch (nds->m_op) {
1405 case NDR_M_OP_MARSHALL:
1406 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1407 return (0);
1408
1409 case NDR_M_OP_UNMARSHALL:
1410 rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1411 nds->swap, outer_ref);
1412 break;
1413
1414 default:
1415 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1416 return (0);
1417 }
1418
1419 return (rc);
1420 }
1421
1422 int
ndr_outer_poke_sizing(ndr_ref_t * outer_ref,unsigned offset,unsigned long * sizing_p)1423 ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
1424 unsigned long *sizing_p)
1425 {
1426 ndr_stream_t *nds = outer_ref->stream;
1427 unsigned long pdu_offset;
1428 int rc;
1429
1430 pdu_offset = outer_ref->pdu_offset + offset;
1431
1432 if (pdu_offset < nds->outer_current->pdu_offset ||
1433 pdu_offset > nds->outer_current->pdu_end_offset ||
1434 pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1435 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1436 return (0);
1437 }
1438
1439 switch (nds->m_op) {
1440 case NDR_M_OP_MARSHALL:
1441 rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1442 nds->swap, outer_ref);
1443 break;
1444
1445 case NDR_M_OP_UNMARSHALL:
1446 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1447 return (0);
1448
1449 default:
1450 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1451 return (0);
1452 }
1453
1454 return (rc);
1455 }
1456
1457 /*
1458 * All OUTER constructs begin on a mod4 (dword) boundary - except
1459 * for the ones that don't: some MSRPC calls appear to use word or
1460 * packed alignment. Strings appear to be dword aligned.
1461 */
1462 int
ndr_outer_align(ndr_ref_t * outer_ref)1463 ndr_outer_align(ndr_ref_t *outer_ref)
1464 {
1465 ndr_stream_t *nds = outer_ref->stream;
1466 int rc;
1467 unsigned n_pad;
1468 unsigned align;
1469
1470 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1471 align = outer_ref->ti->alignment;
1472 n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
1473 } else {
1474 n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
1475 }
1476
1477 if ((outer_ref->ti->type_flags & NDR_F_FAKE) != 0 || n_pad == 0)
1478 return (1); /* already aligned, often the case */
1479
1480 if (!ndr_outer_grow(outer_ref, n_pad))
1481 return (0); /* error already set */
1482
1483 switch (nds->m_op) {
1484 case NDR_M_OP_MARSHALL:
1485 rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
1486 if (!rc) {
1487 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1488 return (0);
1489 }
1490 break;
1491
1492 case NDR_M_OP_UNMARSHALL:
1493 break;
1494
1495 default:
1496 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1497 return (0);
1498 }
1499
1500 nds->pdu_scan_offset += n_pad;
1501 return (1);
1502 }
1503
1504 int
ndr_outer_grow(ndr_ref_t * outer_ref,unsigned n_total)1505 ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
1506 {
1507 ndr_stream_t *nds = outer_ref->stream;
1508 unsigned long pdu_want_size;
1509 int rc, is_ok = 0;
1510
1511 pdu_want_size = nds->pdu_scan_offset + n_total;
1512
1513 if (pdu_want_size <= nds->pdu_max_size) {
1514 is_ok = 1;
1515 }
1516
1517 switch (nds->m_op) {
1518 case NDR_M_OP_MARSHALL:
1519 if (is_ok)
1520 break;
1521 rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
1522 if (!rc) {
1523 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1524 return (0);
1525 }
1526 break;
1527
1528 case NDR_M_OP_UNMARSHALL:
1529 if (is_ok)
1530 break;
1531 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1532 return (0);
1533
1534 default:
1535 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1536 return (0);
1537 }
1538
1539 if (nds->pdu_size < pdu_want_size)
1540 nds->pdu_size = pdu_want_size;
1541
1542 outer_ref->pdu_end_offset = pdu_want_size;
1543 return (1);
1544 }
1545
1546 /*
1547 * Some 'outer' constructs incorrectly align the entire construct
1548 * on a 4-byte boundary, when each of its members needs to be
1549 * aligned separately. This function handles aligning 'inner'
1550 * members on their natural alignment boundary.
1551 *
1552 * NOTE: This assumes it is not being used for headers.
1553 * Headers present some unique concerns that this may not
1554 * adequately address (e.g. reserved space, pdu_body_offset).
1555 */
1556 int
ndr_inner_align(ndr_ref_t * arg_ref)1557 ndr_inner_align(ndr_ref_t *arg_ref)
1558 {
1559 ndr_stream_t *nds = arg_ref->stream;
1560 int rc;
1561 unsigned n_pad;
1562
1563 n_pad = ((arg_ref->ti->alignment + 1) - arg_ref->pdu_offset) &
1564 arg_ref->ti->alignment;
1565
1566 if (n_pad == 0)
1567 return (1); /* already aligned, often the case */
1568
1569 if (!ndr_outer_grow(arg_ref->enclosing, n_pad))
1570 return (0); /* error already set */
1571
1572 switch (nds->m_op) {
1573 case NDR_M_OP_MARSHALL:
1574 rc = NDS_PAD_PDU(nds, arg_ref->pdu_offset, n_pad, arg_ref);
1575 if (!rc) {
1576 NDR_SET_ERROR(arg_ref, NDR_ERR_PAD_FAILED);
1577 return (0);
1578 }
1579 break;
1580
1581 case NDR_M_OP_UNMARSHALL:
1582 break;
1583
1584 default:
1585 NDR_SET_ERROR(arg_ref, NDR_ERR_M_OP_INVALID);
1586 return (0);
1587 }
1588
1589 /* All current and future offsets need to advance */
1590 arg_ref->enclosing->pdu_offset += n_pad;
1591 arg_ref->pdu_offset += n_pad;
1592 /* ndr_outer_grow changed pdu_end_offset */
1593 nds->pdu_scan_offset += n_pad;
1594 return (1);
1595 }
1596
1597 /*
1598 * INNER ELEMENTS
1599 *
1600 * The local datum (arg_ref->datum) already exists, there is no need to
1601 * malloc() it. The datum should point at a member of a structure.
1602 *
1603 * For the most part, ndr_inner() and its helpers are just a sanity
1604 * check. The underlying ti->ndr_func() could be called immediately
1605 * for non-pointer elements. For the sake of robustness, we detect
1606 * run-time errors here. Most of the situations this protects against
1607 * have already been checked by the IDL compiler. This is also a
1608 * common point for processing of all data, and so is a convenient
1609 * place to work from for debugging.
1610 */
1611 int
ndr_inner(ndr_ref_t * arg_ref)1612 ndr_inner(ndr_ref_t *arg_ref)
1613 {
1614 ndr_typeinfo_t *ti = arg_ref->ti;
1615 int is_varlen = ti->pdu_size_variable_part;
1616 int is_union = NDR_IS_UNION(ti);
1617 int error = NDR_ERR_INNER_PARAMS_BAD;
1618 int params;
1619
1620 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1621
1622 /*
1623 * Switched unions are meant to be converted to and from encapsulated
1624 * structures on the wire. However, NDRGEN doesn't implement this.
1625 * As a result, our interface definitions use 'fake' structures
1626 * to represent switched unions.
1627 * This causes the structure to be aligned on a struct (4 byte)
1628 * boundary, with none of its members having separate alignment -
1629 * but that's not correct. Each of its members has its own,
1630 * natural alignment, and we need to honor that.
1631 * That happens here.
1632 */
1633 if (arg_ref->enclosing != NULL &&
1634 (arg_ref->enclosing->ti->type_flags & NDR_F_FAKE) != 0 &&
1635 !ndr_inner_align(arg_ref))
1636 return (0); /* error already set */
1637
1638 switch (params) {
1639 case NDR_F_NONE:
1640 if (is_union) {
1641 error = NDR_ERR_SWITCH_VALUE_MISSING;
1642 break;
1643 }
1644 return (*ti->ndr_func)(arg_ref);
1645
1646 case NDR_F_SIZE_IS:
1647 case NDR_F_DIMENSION_IS:
1648 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */
1649 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1650 if (is_varlen) {
1651 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1652 break;
1653 }
1654 if (is_union) {
1655 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1656 break;
1657 }
1658 if (params & NDR_F_IS_POINTER)
1659 return (ndr_inner_pointer(arg_ref));
1660 else if (params & NDR_F_IS_REFERENCE)
1661 return (ndr_inner_reference(arg_ref));
1662 else
1663 return (ndr_inner_array(arg_ref));
1664
1665 case NDR_F_IS_POINTER: /* type is pointer to one something */
1666 if (is_union) {
1667 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1668 break;
1669 }
1670 return (ndr_inner_pointer(arg_ref));
1671
1672 case NDR_F_IS_REFERENCE: /* type is pointer to one something */
1673 if (is_union) {
1674 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1675 break;
1676 }
1677 return (ndr_inner_reference(arg_ref));
1678
1679 case NDR_F_SWITCH_IS:
1680 if (!is_union) {
1681 error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1682 break;
1683 }
1684 return (*ti->ndr_func)(arg_ref);
1685
1686 default:
1687 error = NDR_ERR_INNER_PARAMS_BAD;
1688 break;
1689 }
1690
1691 /*
1692 * If we get here, something is wrong. Most likely,
1693 * the params flags do not match
1694 */
1695 NDR_SET_ERROR(arg_ref, error);
1696 return (0);
1697 }
1698
1699 int
ndr_inner_pointer(ndr_ref_t * arg_ref)1700 ndr_inner_pointer(ndr_ref_t *arg_ref)
1701 {
1702 ndr_stream_t *nds = arg_ref->stream;
1703 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1704 char **valpp = (char **)arg_ref->datum;
1705 ndr_ref_t *outer_ref;
1706
1707 if (!ndr__ulong(arg_ref))
1708 return (0); /* error */
1709 if (!*valpp)
1710 return (1); /* NULL pointer */
1711
1712 outer_ref = ndr_enter_outer_queue(arg_ref);
1713 if (!outer_ref)
1714 return (0); /* error already set */
1715
1716 /*
1717 * Move advice in inner_flags to outer_flags.
1718 * Retain pointer flag for conformant arrays.
1719 */
1720 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1721 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1722 outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1723 #ifdef NDR_INNER_PTR_NOT_YET
1724 outer_ref->outer_flags |= NDR_F_BACKPTR;
1725 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1726 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1727 }
1728 #endif /* NDR_INNER_PTR_NOT_YET */
1729
1730 outer_ref->backptr = valpp;
1731
1732 switch (nds->m_op) {
1733 case NDR_M_OP_MARSHALL:
1734 outer_ref->datum = *valpp;
1735 break;
1736
1737 case NDR_M_OP_UNMARSHALL:
1738 /*
1739 * This is probably wrong if the application allocated
1740 * memory in advance. Indicate no value for now.
1741 * ONC RPC handles this case.
1742 */
1743 *valpp = 0;
1744 outer_ref->datum = 0;
1745 break;
1746 }
1747
1748 return (1); /* pointer dereference scheduled */
1749 }
1750
1751 int
ndr_inner_reference(ndr_ref_t * arg_ref)1752 ndr_inner_reference(ndr_ref_t *arg_ref)
1753 {
1754 ndr_stream_t *nds = arg_ref->stream;
1755 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1756 char **valpp = (char **)arg_ref->datum;
1757 ndr_ref_t *outer_ref;
1758
1759 outer_ref = ndr_enter_outer_queue(arg_ref);
1760 if (!outer_ref)
1761 return (0); /* error already set */
1762
1763 /*
1764 * Move advice in inner_flags to outer_flags.
1765 * Retain reference flag for conformant arrays.
1766 */
1767 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1768 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1769 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1770 #ifdef NDR_INNER_REF_NOT_YET
1771 outer_ref->outer_flags |= NDR_F_BACKPTR;
1772 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1773 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1774 }
1775 #endif /* NDR_INNER_REF_NOT_YET */
1776
1777 outer_ref->backptr = valpp;
1778
1779 switch (nds->m_op) {
1780 case NDR_M_OP_MARSHALL:
1781 outer_ref->datum = *valpp;
1782 break;
1783
1784 case NDR_M_OP_UNMARSHALL:
1785 /*
1786 * This is probably wrong if the application allocated
1787 * memory in advance. Indicate no value for now.
1788 * ONC RPC handles this case.
1789 */
1790 *valpp = 0;
1791 outer_ref->datum = 0;
1792 break;
1793 }
1794
1795 return (1); /* pointer dereference scheduled */
1796 }
1797
1798 int
ndr_inner_array(ndr_ref_t * encl_ref)1799 ndr_inner_array(ndr_ref_t *encl_ref)
1800 {
1801 ndr_typeinfo_t *ti = encl_ref->ti;
1802 ndr_ref_t myref;
1803 unsigned long pdu_offset = encl_ref->pdu_offset;
1804 unsigned long n_elem;
1805 unsigned long i;
1806 char name[30];
1807
1808 if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1809 /* now is the time to check/set size */
1810 if (!ndr_size_is(encl_ref))
1811 return (0); /* error already set */
1812 n_elem = encl_ref->size_is;
1813 } else {
1814 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1815 n_elem = encl_ref->dimension_is;
1816 }
1817
1818 bzero(&myref, sizeof (myref));
1819 myref.enclosing = encl_ref;
1820 myref.stream = encl_ref->stream;
1821 myref.packed_alignment = 0;
1822 myref.ti = ti;
1823 myref.inner_flags = NDR_F_NONE;
1824
1825 for (i = 0; i < n_elem; i++) {
1826 (void) snprintf(name, sizeof (name), "[%lu]", i);
1827 myref.name = name;
1828 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1829 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1830
1831 if (!ndr_inner(&myref))
1832 return (0);
1833 }
1834
1835 return (1);
1836 }
1837
1838
1839 /*
1840 * BASIC TYPES
1841 */
1842 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1843 extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
1844 ndr_typeinfo_t ndt_##TYPE = { \
1845 1, /* NDR version */ \
1846 (SIZE)-1, /* alignment */ \
1847 NDR_F_NONE, /* flags */ \
1848 ndr_##TYPE, /* ndr_func */ \
1849 SIZE, /* pdu_size_fixed_part */ \
1850 0, /* pdu_size_variable_part */ \
1851 SIZE, /* c_size_fixed_part */ \
1852 0, /* c_size_variable_part */ \
1853 }; \
1854 int ndr_##TYPE(struct ndr_reference *ref) { \
1855 return (ndr_basic_integer(ref, SIZE)); \
1856 }
1857
1858 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
1859 extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
1860 ndr_typeinfo_t ndt_s##TYPE = { \
1861 1, /* NDR version */ \
1862 (SIZE)-1, /* alignment */ \
1863 NDR_F_STRING, /* flags */ \
1864 ndr_s##TYPE, /* ndr_func */ \
1865 0, /* pdu_size_fixed_part */ \
1866 SIZE, /* pdu_size_variable_part */ \
1867 0, /* c_size_fixed_part */ \
1868 SIZE, /* c_size_variable_part */ \
1869 }; \
1870 int ndr_s##TYPE(struct ndr_reference *ref) { \
1871 return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
1872 }
1873
1874 #define MAKE_BASIC_TYPE(TYPE, SIZE) \
1875 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1876 MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1877
1878 int ndr_basic_integer(ndr_ref_t *, unsigned);
1879 int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
1880
1881 /* BEGIN CSTYLED */
1882 /* Comments to be nice to those searching for these types. */
1883 MAKE_BASIC_TYPE(_char, 1) /* ndt__char, ndt_s_char */
1884 MAKE_BASIC_TYPE(_uchar, 1) /* ndt__uchar, ndt_s_uchar */
1885 MAKE_BASIC_TYPE(_short, 2) /* ndt__short, ndt_s_short */
1886 MAKE_BASIC_TYPE(_ushort, 2) /* ndt__ushort, ndt_s_ushort */
1887 MAKE_BASIC_TYPE(_long, 4) /* ndt__long, ndt_s_long */
1888 MAKE_BASIC_TYPE(_ulong, 4) /* ndt__ulong, ndt_s_ulong */
1889
1890 MAKE_BASIC_TYPE_BASE(_wchar, 2) /* ndt__wchar, ndt_s_wchar */
1891 /* END CSTYLED */
1892
1893 int
ndr_basic_integer(ndr_ref_t * ref,unsigned size)1894 ndr_basic_integer(ndr_ref_t *ref, unsigned size)
1895 {
1896 ndr_stream_t *nds = ref->stream;
1897 char *valp = (char *)ref->datum;
1898 int rc;
1899
1900 switch (nds->m_op) {
1901 case NDR_M_OP_MARSHALL:
1902 rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
1903 valp, nds->swap, ref);
1904 break;
1905
1906 case NDR_M_OP_UNMARSHALL:
1907 rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
1908 valp, nds->swap, ref);
1909 break;
1910
1911 default:
1912 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1913 return (0);
1914 }
1915
1916 return (rc);
1917 }
1918
1919 int
ndr_string_basic_integer(ndr_ref_t * encl_ref,ndr_typeinfo_t * type_under)1920 ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
1921 {
1922 unsigned long pdu_offset = encl_ref->pdu_offset;
1923 unsigned size = type_under->pdu_size_fixed_part;
1924 char *valp;
1925 ndr_ref_t myref;
1926 unsigned long i;
1927 long sense = 0;
1928 char name[30];
1929
1930 assert(size != 0);
1931
1932 bzero(&myref, sizeof (myref));
1933 myref.enclosing = encl_ref;
1934 myref.stream = encl_ref->stream;
1935 myref.packed_alignment = 0;
1936 myref.ti = type_under;
1937 myref.inner_flags = NDR_F_NONE;
1938 myref.name = name;
1939
1940 for (i = 0; i < NDR_STRING_MAX; i++) {
1941 (void) snprintf(name, sizeof (name), "[%lu]", i);
1942 myref.pdu_offset = pdu_offset + i * size;
1943 valp = encl_ref->datum + i * size;
1944 myref.datum = valp;
1945
1946 if (!ndr_inner(&myref))
1947 return (0);
1948
1949 switch (size) {
1950 case 1: sense = *valp; break;
1951 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1952 case 2: sense = *(short *)valp; break;
1953 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1954 case 4: sense = *(long *)valp; break;
1955 }
1956
1957 if (!sense)
1958 break;
1959 }
1960
1961 return (1);
1962 }
1963
1964
1965 extern int ndr_s_wchar(ndr_ref_t *encl_ref);
1966 ndr_typeinfo_t ndt_s_wchar = {
1967 1, /* NDR version */
1968 2-1, /* alignment */
1969 NDR_F_STRING, /* flags */
1970 ndr_s_wchar, /* ndr_func */
1971 0, /* pdu_size_fixed_part */
1972 2, /* pdu_size_variable_part */
1973 0, /* c_size_fixed_part */
1974 1, /* c_size_variable_part */
1975 };
1976
1977
1978 /*
1979 * Hand coded wchar function because all strings are transported
1980 * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1981 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1982 * convert from wide characters to multi-byte.
1983 *
1984 * The most critical thing to get right in this function is to
1985 * marshall or unmarshall _exactly_ the number of elements the
1986 * OtW length specifies, as saved by the caller in: strlen_is.
1987 * Doing otherwise would leave us positioned at the wrong place
1988 * in the data stream for whatever follows this. Note that the
1989 * string data covered by strlen_is may or may not include any
1990 * null termination, but the converted string provided by the
1991 * caller or returned always has a null terminator.
1992 */
1993 int
ndr_s_wchar(ndr_ref_t * encl_ref)1994 ndr_s_wchar(ndr_ref_t *encl_ref)
1995 {
1996 ndr_stream_t *nds = encl_ref->stream;
1997 char *valp = encl_ref->datum;
1998 ndr_ref_t myref;
1999 char name[30];
2000 ndr_wchar_t wcs[NDR_STRING_MAX+1];
2001 size_t i, slen, wlen;
2002
2003 /* This is enforced in ndr_outer_string() */
2004 assert(encl_ref->strlen_is <= NDR_STRING_MAX);
2005
2006 if (nds->m_op == NDR_M_OP_UNMARSHALL) {
2007 /*
2008 * To avoid problems with zero length strings
2009 * we can just null terminate here and be done.
2010 */
2011 if (encl_ref->strlen_is == 0) {
2012 encl_ref->datum[0] = '\0';
2013 return (1);
2014 }
2015 }
2016
2017 /*
2018 * If we're marshalling, convert the given string
2019 * from UTF-8 into a local UCS-2 string.
2020 */
2021 if (nds->m_op == NDR_M_OP_MARSHALL) {
2022 wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
2023 if (wlen == (size_t)-1)
2024 return (0);
2025 /*
2026 * Add a nulls to make strlen_is.
2027 * (always zero or one of them)
2028 * Then null terminate at wlen,
2029 * just for debug convenience.
2030 */
2031 while (wlen < encl_ref->strlen_is)
2032 wcs[wlen++] = 0;
2033 wcs[wlen] = 0;
2034 }
2035
2036 /*
2037 * Copy wire data to or from the local wc string.
2038 * Always exactly strlen_is elements.
2039 */
2040 bzero(&myref, sizeof (myref));
2041 myref.enclosing = encl_ref;
2042 myref.stream = encl_ref->stream;
2043 myref.packed_alignment = 0;
2044 myref.ti = &ndt__wchar;
2045 myref.inner_flags = NDR_F_NONE;
2046 myref.name = name;
2047 myref.pdu_offset = encl_ref->pdu_offset;
2048 myref.datum = (char *)wcs;
2049 wlen = encl_ref->strlen_is;
2050
2051 for (i = 0; i < wlen; i++) {
2052 (void) snprintf(name, sizeof (name), "[%lu]", i);
2053 if (!ndr_inner(&myref))
2054 return (0);
2055 myref.pdu_offset += sizeof (ndr_wchar_t);
2056 myref.datum += sizeof (ndr_wchar_t);
2057 }
2058
2059 /*
2060 * If this is unmarshall, convert the local UCS-2 string
2061 * into a UTF-8 string in the caller's buffer. The caller
2062 * previously determined the space required and provides a
2063 * buffer of sufficient size.
2064 */
2065 if (nds->m_op == NDR_M_OP_UNMARSHALL) {
2066 wcs[wlen] = 0;
2067 slen = encl_ref->size_is * NDR_MB_CHAR_MAX;
2068 slen = ndr__wcstombs(valp, wcs, slen);
2069 if (slen == (size_t)-1)
2070 return (0);
2071 valp[slen] = '\0';
2072 }
2073
2074 return (1);
2075 }
2076
2077 /*
2078 * Converts a multibyte character string to a little-endian, wide-char
2079 * string. No more than nwchars wide characters are stored.
2080 * A terminating null wide character is appended if there is room.
2081 *
2082 * Returns the number of wide characters converted, not counting
2083 * any terminating null wide character. Returns -1 if an invalid
2084 * multibyte character is encountered.
2085 */
2086 /* ARGSUSED */
2087 size_t
ndr_mbstowcs(ndr_stream_t * nds,ndr_wchar_t * wcs,const char * mbs,size_t nwchars)2088 ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
2089 size_t nwchars)
2090 {
2091 size_t len;
2092
2093 #ifdef _BIG_ENDIAN
2094 if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
2095 /* Make WC string in LE order. */
2096 len = ndr__mbstowcs_le(wcs, mbs, nwchars);
2097 } else
2098 #endif
2099 len = ndr__mbstowcs(wcs, mbs, nwchars);
2100
2101 return (len);
2102 }
2103