6429 SMB domain join doesn't work with libreSSL
[unleashed.git] / usr / src / lib / libmlrpc / common / ndr_process.c
blob3188500a8b3bf650e766e747f6fa8b1945a49623
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
29 * Network Data Representation (NDR) is a compatible subset of the DCE RPC
30 * and MSRPC NDR. NDR is used to move parameters consisting of
31 * complicated trees of data constructs between an RPC client and server.
34 #include <sys/byteorder.h>
35 #include <strings.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
41 #include <libmlrpc.h>
42 #include <ndr_wchar.h>
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)
49 extern ndr_typeinfo_t ndt_s_wchar;
52 * The following synopsis describes the terms TOP-MOST, OUTER and INNER.
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.
60 * This is most easily demonstrated with a short example.
61 * Consider these structures:
63 * struct top_param {
64 * long level;
65 * struct list * head;
66 * long count;
67 * };
69 * struct list {
70 * struct list * next;
71 * char * str; // a string
72 * };
74 * Now, consider an instance tree like this:
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 * +---------+ +-------+ +-------+
84 * The DCE(MS)/RPC Stub Data encoding for the tree is the following.
85 * The vertical bars (|) indicate OUTER construct boundaries.
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
93 * Here's what to notice:
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.
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.
110 * - The INNER constructs are simply the members of an OUTER construct.
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:
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
124 * More details about each TOP-MOST, OUTER, and INNER constructs appear
125 * throughout this source file near where such constructs are processed.
127 * NDR_REFERENCE
129 * The primary object for NDR is the ndr_ref_t.
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.
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.
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.
149 * QUEUE OF OUTER REFERENCES
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.
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.
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.
168 * During some point in the processing, the queue looks like this:
170 * outer_current -------v
171 * outer_queue_head --> list#1 --0
172 * outer_queue_tailp ---------&
174 * When the pointer #1.next is encountered, and entry is added to the
175 * queue,
177 * outer_current -------v
178 * outer_queue_head --> list#1 --> list#2 --0
179 * outer_queue_tailp --------------------&
181 * and the members of #1 continue to be processed, which encounters
182 * #1.str:
184 * outer_current -------v
185 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
186 * outer_queue_tailp ------------------------------&
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:
191 * outer_current ------------------v
192 * outer_queue_head --> list#1 --> list#2 --> "foo" --0
193 * outer_queue_tailp --------------------&
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:
200 * outer_current ------------------v
201 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
202 * outer_queue_tailp ------------------------------&
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:
208 * outer_current -----------------------------v
209 * outer_queue_head --> list#1 --> list#2 --> "bar" --> "foo" --0
210 * outer_queue_tailp ------------------------------&
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.
216 * When the queue is drained (current->next==0), processing continues
217 * with the next TOP-MOST member.
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.
225 static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
226 extern int ndr__ulong(ndr_ref_t *);
229 * TOP-MOST ELEMENTS
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.
236 * After the element is transferred, the outer_queue is drained.
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.
242 ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
244 ndr_ref_t myref;
246 bzero(&myref, sizeof (myref));
247 myref.stream = nds;
248 myref.datum = datum;
249 myref.name = "PROCESS";
250 myref.ti = ti;
252 return (ndr_topmost(&myref));
256 ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
258 ndr_ref_t myref;
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;
268 if (ti->type_flags != NDR_F_INTERFACE) {
269 NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
270 return (0);
273 return ((*ti->ndr_func)(&myref));
277 ndr_params(ndr_ref_t *params_ref)
279 ndr_typeinfo_t *ti = params_ref->ti;
281 if (ti->type_flags == NDR_F_OPERATION)
282 return (*ti->ndr_func) (params_ref);
283 else
284 return (ndr_topmost(params_ref));
288 ndr_topmost(ndr_ref_t *top_ref)
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;
300 assert(top_ref);
301 assert(top_ref->stream);
302 assert(top_ref->ti);
304 nds = top_ref->stream;
305 ti = top_ref->ti;
307 is_varlen = ti->pdu_size_variable_part;
308 is_string = NDR_IS_STRING(ti);
310 assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
311 assert(!nds->outer_current);
313 params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
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);
323 n_fixed = ti->pdu_size_fixed_part;
324 break;
326 case NDR_F_SIZE_IS:
327 error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
328 NDR_SET_ERROR(outer_ref, error);
329 return (0);
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);
337 n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
338 break;
340 case NDR_F_IS_POINTER:
341 case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
342 n_fixed = 4;
343 break;
345 case NDR_F_IS_REFERENCE:
346 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
347 n_fixed = 0;
348 break;
350 default:
351 error = NDR_ERR_OUTER_PARAMS_BAD;
352 NDR_SET_ERROR(outer_ref, error);
353 return (0);
356 outer_ref = ndr_enter_outer_queue(top_ref);
357 if (!outer_ref)
358 return (0); /* error already set */
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.
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;
372 /* All outer constructs start on a mod4 (longword) boundary */
373 if (!ndr_outer_align(outer_ref))
374 return (0); /* error already set */
376 /* Regardless of what it is, this is where it starts */
377 outer_ref->pdu_offset = nds->pdu_scan_offset;
379 rc = ndr_outer_grow(outer_ref, n_fixed);
380 if (!rc)
381 return (0); /* error already set */
383 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
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;
390 /* do the topmost member */
391 rc = ndr_inner(outer_ref);
392 if (!rc)
393 return (0); /* error already set */
395 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
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));
402 static ndr_ref_t *
403 ndr_enter_outer_queue(ndr_ref_t *arg_ref)
405 ndr_stream_t *nds = arg_ref->stream;
406 ndr_ref_t *outer_ref;
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);
415 *outer_ref = *arg_ref;
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;
424 assert(nds->outer_queue_tailp);
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);
433 ndr_run_outer_queue(ndr_stream_t *nds)
435 while (nds->outer_current) {
436 nds->outer_queue_tailp = &nds->outer_current->next;
438 if (!ndr_outer(nds->outer_current))
439 return (0);
441 nds->outer_current = nds->outer_current->next;
444 return (1);
448 * OUTER CONSTRUCTS
450 * OUTER constructs are where the real work is, which stems from the
451 * variable-length potential.
453 * DCE(MS)/RPC VARIABLE LENGTH -- CONFORMANT, VARYING, VARYING/CONFORMANT
455 * DCE(MS)/RPC provides for three forms of variable length: CONFORMANT,
456 * VARYING, and VARYING/CONFORMANT.
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.
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.
474 * CONFORMANT CONSTRUCTS -- VARIABLE LENGTH ARRAYS START THE SHOW
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:
480 * struct credentials {
481 * ulong uid, gid;
482 * ulong n_gids;
483 * [size_is(n_gids)]
484 * ulong gids[*]; // variable-length.
485 * };
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:
491 * struct conformant_header {
492 * ulong size_is;
493 * };
495 * (Multi-dimensional CONFORMANT arrays have a similar header for each
496 * dimension - not implemented).
498 * Example CONFORMANT construct:
500 * struct user {
501 * char * name;
502 * struct credentials cred; // see above
503 * };
505 * Consider the data tree:
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 * +--------+
519 * The OUTER construct in the Stub Data would be:
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 ---->|
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]
531 * VARYING CONSTRUCTS -- NOT IMPLEMENTED
533 * VARYING constructs have the following header:
535 * struct varying_header {
536 * ulong first_is;
537 * ulong length_is;
538 * };
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.
545 * N.B. Constructs may contain one CONFORMANT element, which is always
546 * last, but may contain many VARYING elements, which can be anywhere.
548 * VARYING CONFORMANT constructs have the sizing headers arranged like
549 * this:
551 * struct conformant_header all_conformant[N_CONFORMANT_DIM];
552 * struct varying_header all_varying[N_VARYING_ELEMS_AND_DIMS];
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.
558 * A good example of a VARYING/CONFORMANT data structure is the UNIX
559 * directory entry:
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 * };
570 * STRINGS ARE A SPECIAL CASE
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:
577 * struct string_header {
578 * ulong size_is;
579 * ulong first_is; // always 0
580 * ulong length_is; // always same as size_is
581 * };
583 * If general support for VARYING and VARYING/CONFORMANT mechanisms is
584 * implemented, we probably won't need the strings special case.
587 ndr_outer(ndr_ref_t *outer_ref)
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;
597 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
599 NDR_TATTLE(outer_ref, "--OUTER--");
601 /* All outer constructs start on a mod4 (longword) boundary */
602 if (!ndr_outer_align(outer_ref))
603 return (0); /* error already set */
605 /* Regardless of what it is, this is where it starts */
606 outer_ref->pdu_offset = nds->pdu_scan_offset;
608 if (is_union) {
609 error = NDR_ERR_OUTER_UNION_ILLEGAL;
610 NDR_SET_ERROR(outer_ref, error);
611 return (0);
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));
621 return (ndr_outer_fixed(outer_ref));
623 case NDR_F_SIZE_IS:
624 case NDR_F_DIMENSION_IS:
625 case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
626 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
627 if (is_varlen) {
628 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
629 break;
632 if (params & NDR_F_SIZE_IS)
633 return (ndr_outer_conformant_array(outer_ref));
634 else
635 return (ndr_outer_fixed_array(outer_ref));
637 default:
638 error = NDR_ERR_OUTER_PARAMS_BAD;
639 break;
643 * If we get here, something is wrong. Most likely,
644 * the params flags do not match.
646 NDR_SET_ERROR(outer_ref, error);
647 return (0);
651 ndr_outer_fixed(ndr_ref_t *outer_ref)
653 ndr_stream_t *nds = outer_ref->stream;
654 ndr_typeinfo_t *ti = outer_ref->ti;
655 ndr_ref_t myref;
656 char *valp = NULL;
657 int is_varlen = ti->pdu_size_variable_part;
658 int is_union = NDR_IS_UNION(ti);
659 int is_string = NDR_IS_STRING(ti);
660 int rc;
661 unsigned n_hdr;
662 unsigned n_fixed;
663 unsigned n_variable;
664 unsigned n_alloc;
665 unsigned n_pdu_total;
666 int params;
668 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
670 assert(!is_varlen && !is_string && !is_union);
671 assert(params == NDR_F_NONE);
673 /* no header for this */
674 n_hdr = 0;
676 /* fixed part -- exactly one of these */
677 n_fixed = ti->pdu_size_fixed_part;
678 assert(n_fixed > 0);
680 /* variable part -- exactly none of these */
681 n_variable = 0;
683 /* sum them up to determine the PDU space required */
684 n_pdu_total = n_hdr + n_fixed + n_variable;
686 /* similar sum to determine how much local memory is required */
687 n_alloc = n_fixed + n_variable;
689 rc = ndr_outer_grow(outer_ref, n_pdu_total);
690 if (!rc)
691 return (rc); /* error already set */
693 switch (nds->m_op) {
694 case NDR_M_OP_MARSHALL:
695 valp = outer_ref->datum;
696 if (!valp) {
697 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
698 return (0);
700 if (outer_ref->backptr)
701 assert(valp == *outer_ref->backptr);
702 break;
704 case NDR_M_OP_UNMARSHALL:
705 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
706 if (!valp) {
707 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
708 return (0);
710 if (outer_ref->backptr)
711 *outer_ref->backptr = valp;
712 outer_ref->datum = valp;
713 break;
715 default:
716 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
717 return (0);
720 bzero(&myref, sizeof (myref));
721 myref.stream = nds;
722 myref.enclosing = outer_ref;
723 myref.ti = outer_ref->ti;
724 myref.datum = outer_ref->datum;
725 myref.name = "FIXED-VALUE";
726 myref.outer_flags = NDR_F_NONE;
727 myref.inner_flags = NDR_F_NONE;
729 myref.pdu_offset = outer_ref->pdu_offset;
730 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
732 rc = ndr_inner(&myref);
733 if (!rc)
734 return (rc); /* error already set */
736 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
737 return (1);
741 ndr_outer_fixed_array(ndr_ref_t *outer_ref)
743 ndr_stream_t *nds = outer_ref->stream;
744 ndr_typeinfo_t *ti = outer_ref->ti;
745 ndr_ref_t myref;
746 char *valp = NULL;
747 int is_varlen = ti->pdu_size_variable_part;
748 int is_union = NDR_IS_UNION(ti);
749 int is_string = NDR_IS_STRING(ti);
750 int rc;
751 unsigned n_hdr;
752 unsigned n_fixed;
753 unsigned n_variable;
754 unsigned n_alloc;
755 unsigned n_pdu_total;
756 int params;
758 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
760 assert(!is_varlen && !is_string && !is_union);
761 assert(params == NDR_F_DIMENSION_IS);
763 /* no header for this */
764 n_hdr = 0;
766 /* fixed part -- exactly dimension_is of these */
767 n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
768 assert(n_fixed > 0);
770 /* variable part -- exactly none of these */
771 n_variable = 0;
773 /* sum them up to determine the PDU space required */
774 n_pdu_total = n_hdr + n_fixed + n_variable;
776 /* similar sum to determine how much local memory is required */
777 n_alloc = n_fixed + n_variable;
779 rc = ndr_outer_grow(outer_ref, n_pdu_total);
780 if (!rc)
781 return (rc); /* error already set */
783 switch (nds->m_op) {
784 case NDR_M_OP_MARSHALL:
785 valp = outer_ref->datum;
786 if (!valp) {
787 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
788 return (0);
790 if (outer_ref->backptr)
791 assert(valp == *outer_ref->backptr);
792 break;
794 case NDR_M_OP_UNMARSHALL:
795 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
796 if (!valp) {
797 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
798 return (0);
800 if (outer_ref->backptr)
801 *outer_ref->backptr = valp;
802 outer_ref->datum = valp;
803 break;
805 default:
806 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
807 return (0);
810 bzero(&myref, sizeof (myref));
811 myref.stream = nds;
812 myref.enclosing = outer_ref;
813 myref.ti = outer_ref->ti;
814 myref.datum = outer_ref->datum;
815 myref.name = "FIXED-ARRAY";
816 myref.outer_flags = NDR_F_NONE;
817 myref.inner_flags = NDR_F_DIMENSION_IS;
818 myref.dimension_is = outer_ref->dimension_is;
820 myref.pdu_offset = outer_ref->pdu_offset;
821 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
823 rc = ndr_inner(&myref);
824 if (!rc)
825 return (rc); /* error already set */
827 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
828 return (1);
832 ndr_outer_conformant_array(ndr_ref_t *outer_ref)
834 ndr_stream_t *nds = outer_ref->stream;
835 ndr_typeinfo_t *ti = outer_ref->ti;
836 ndr_ref_t myref;
837 char *valp = NULL;
838 int is_varlen = ti->pdu_size_variable_part;
839 int is_union = NDR_IS_UNION(ti);
840 int is_string = NDR_IS_STRING(ti);
841 unsigned long size_is;
842 int rc;
843 unsigned n_hdr;
844 unsigned n_fixed;
845 unsigned n_variable;
846 unsigned n_alloc;
847 unsigned n_pdu_total;
848 unsigned n_ptr_offset;
849 int params;
851 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
853 assert(!is_varlen && !is_string && !is_union);
854 assert(params & NDR_F_SIZE_IS);
856 /* conformant header for this */
857 n_hdr = 4;
859 /* fixed part -- exactly none of these */
860 n_fixed = 0;
862 /* variable part -- exactly size_of of these */
863 /* notice that it is the **fixed** size of the ti */
864 n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
866 /* sum them up to determine the PDU space required */
867 n_pdu_total = n_hdr + n_fixed + n_variable;
869 /* similar sum to determine how much local memory is required */
870 n_alloc = n_fixed + n_variable;
872 rc = ndr_outer_grow(outer_ref, n_pdu_total);
873 if (!rc)
874 return (rc); /* error already set */
876 switch (nds->m_op) {
877 case NDR_M_OP_MARSHALL:
878 size_is = outer_ref->size_is;
879 rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
880 if (!rc)
881 return (0); /* error already set */
883 valp = outer_ref->datum;
884 if (!valp) {
885 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
886 return (0);
888 if (outer_ref->backptr)
889 assert(valp == *outer_ref->backptr);
890 n_ptr_offset = 4;
891 break;
893 case NDR_M_OP_UNMARSHALL:
894 if (params & NDR_F_IS_REFERENCE) {
895 size_is = outer_ref->size_is;
896 n_ptr_offset = 0;
897 } else {
898 /* NDR_F_IS_POINTER */
899 rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
900 if (!rc)
901 return (0); /* error already set */
903 if (size_is != outer_ref->size_is) {
904 NDR_SET_ERROR(outer_ref,
905 NDR_ERR_SIZE_IS_MISMATCH_PDU);
906 return (0);
909 n_ptr_offset = 4;
912 if (size_is > 0) {
913 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
914 if (!valp) {
915 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
916 return (0);
920 if (outer_ref->backptr)
921 *outer_ref->backptr = valp;
922 outer_ref->datum = valp;
923 break;
925 default:
926 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
927 return (0);
930 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
931 outer_ref->type_flags = NDR_F_NONE;
932 outer_ref->inner_flags = NDR_F_NONE;
934 if (size_is > 0) {
935 bzero(&myref, sizeof (myref));
936 myref.stream = nds;
937 myref.enclosing = outer_ref;
938 myref.ti = outer_ref->ti;
939 myref.datum = outer_ref->datum;
940 myref.name = "CONFORMANT-ARRAY";
941 myref.outer_flags = NDR_F_NONE;
942 myref.inner_flags = NDR_F_SIZE_IS;
943 myref.size_is = outer_ref->size_is;
945 myref.inner_flags = NDR_F_DIMENSION_IS; /* convenient */
946 myref.dimension_is = outer_ref->size_is; /* convenient */
948 myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
950 rc = ndr_inner(&myref);
951 if (!rc)
952 return (rc); /* error already set */
955 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
956 return (1);
960 ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
962 ndr_stream_t *nds = outer_ref->stream;
963 ndr_typeinfo_t *ti = outer_ref->ti;
964 ndr_ref_t myref;
965 char *valp = NULL;
966 int is_varlen = ti->pdu_size_variable_part;
967 int is_union = NDR_IS_UNION(ti);
968 int is_string = NDR_IS_STRING(ti);
969 unsigned long size_is;
970 int rc;
971 unsigned n_hdr;
972 unsigned n_fixed;
973 unsigned n_variable;
974 unsigned n_alloc;
975 unsigned n_pdu_total;
976 int params;
978 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
980 assert(is_varlen && !is_string && !is_union);
981 assert(params == NDR_F_NONE);
983 /* conformant header for this */
984 n_hdr = 4;
986 /* fixed part -- exactly one of these */
987 n_fixed = ti->pdu_size_fixed_part;
989 /* variable part -- exactly size_of of these */
990 n_variable = 0; /* 0 for the moment */
992 /* sum them up to determine the PDU space required */
993 n_pdu_total = n_hdr + n_fixed + n_variable;
995 /* similar sum to determine how much local memory is required */
996 n_alloc = n_fixed + n_variable;
998 /* For the moment, grow enough for the fixed-size part */
999 rc = ndr_outer_grow(outer_ref, n_pdu_total);
1000 if (!rc)
1001 return (rc); /* error already set */
1003 switch (nds->m_op) {
1004 case NDR_M_OP_MARSHALL:
1006 * We don't know the size yet. We have to wait for
1007 * it. Proceed with the fixed-size part, and await
1008 * the call to ndr_size_is().
1010 size_is = 0;
1011 rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1012 if (!rc)
1013 return (0); /* error already set */
1015 valp = outer_ref->datum;
1016 if (!valp) {
1017 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
1018 return (0);
1020 if (outer_ref->backptr)
1021 assert(valp == *outer_ref->backptr);
1022 break;
1024 case NDR_M_OP_UNMARSHALL:
1026 * We know the size of the variable part because
1027 * of the CONFORMANT header. We will verify
1028 * the header against the [size_is(X)] advice
1029 * later when ndr_size_is() is called.
1031 rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
1032 if (!rc)
1033 return (0); /* error already set */
1035 /* recalculate metrics */
1036 n_variable = size_is * ti->pdu_size_variable_part;
1037 n_pdu_total = n_hdr + n_fixed + n_variable;
1038 n_alloc = n_fixed + n_variable;
1040 rc = ndr_outer_grow(outer_ref, n_pdu_total);
1041 if (!rc)
1042 return (rc); /* error already set */
1044 outer_ref->size_is = size_is; /* verified later */
1046 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1047 if (!valp) {
1048 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1049 return (0);
1051 if (outer_ref->backptr)
1052 *outer_ref->backptr = valp;
1053 outer_ref->datum = valp;
1054 break;
1056 default:
1057 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1058 return (0);
1061 outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
1062 outer_ref->type_flags = NDR_F_SIZE_IS; /* indicate pending */
1063 outer_ref->inner_flags = NDR_F_NONE; /* indicate pending */
1065 bzero(&myref, sizeof (myref));
1066 myref.stream = nds;
1067 myref.enclosing = outer_ref;
1068 myref.ti = outer_ref->ti;
1069 myref.datum = outer_ref->datum;
1070 myref.name = "CONFORMANT-CONSTRUCT";
1071 myref.outer_flags = NDR_F_NONE;
1072 myref.inner_flags = NDR_F_NONE;
1073 myref.size_is = outer_ref->size_is;
1075 myref.pdu_offset = outer_ref->pdu_offset + 4;
1077 rc = ndr_inner(&myref);
1078 if (!rc)
1079 return (rc); /* error already set */
1081 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1083 if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
1084 NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
1085 return (0);
1088 return (1);
1092 ndr_size_is(ndr_ref_t *ref)
1094 ndr_stream_t *nds = ref->stream;
1095 ndr_ref_t *outer_ref = nds->outer_current;
1096 ndr_typeinfo_t *ti = outer_ref->ti;
1097 unsigned long size_is;
1098 int rc;
1099 unsigned n_hdr;
1100 unsigned n_fixed;
1101 unsigned n_variable;
1102 unsigned n_pdu_total;
1104 assert(ref->inner_flags & NDR_F_SIZE_IS);
1105 size_is = ref->size_is;
1107 if (outer_ref->type_flags != NDR_F_SIZE_IS) {
1108 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
1109 return (0);
1112 if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
1113 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
1114 return (0);
1117 /* repeat metrics, see ndr_conformant_construct() above */
1118 n_hdr = 4;
1119 n_fixed = ti->pdu_size_fixed_part;
1120 n_variable = size_is * ti->pdu_size_variable_part;
1121 n_pdu_total = n_hdr + n_fixed + n_variable;
1123 rc = ndr_outer_grow(outer_ref, n_pdu_total);
1124 if (!rc)
1125 return (rc); /* error already set */
1127 switch (nds->m_op) {
1128 case NDR_M_OP_MARSHALL:
1130 * We have to set the sizing header and extend
1131 * the size of the PDU (already done).
1133 rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
1134 if (!rc)
1135 return (0); /* error already set */
1136 break;
1138 case NDR_M_OP_UNMARSHALL:
1140 * Allocation done during ndr_conformant_construct().
1141 * All we are doing here is verifying that the
1142 * intended size (ref->size_is) matches the sizing header.
1144 if (size_is != outer_ref->size_is) {
1145 NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
1146 return (0);
1148 break;
1150 default:
1151 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1152 return (0);
1155 outer_ref->inner_flags |= NDR_F_SIZE_IS;
1156 outer_ref->size_is = ref->size_is;
1157 return (1);
1161 ndr_outer_string(ndr_ref_t *outer_ref)
1163 ndr_stream_t *nds = outer_ref->stream;
1164 ndr_typeinfo_t *ti = outer_ref->ti;
1165 ndr_ref_t myref;
1166 char *valp = NULL;
1167 unsigned is_varlen = ti->pdu_size_variable_part;
1168 int is_union = NDR_IS_UNION(ti);
1169 int is_string = NDR_IS_STRING(ti);
1170 int rc;
1171 unsigned n_zeroes;
1172 unsigned ix;
1173 unsigned long size_is;
1174 unsigned long first_is;
1175 unsigned long length_is;
1176 unsigned n_hdr;
1177 unsigned n_fixed;
1178 unsigned n_variable;
1179 unsigned n_alloc;
1180 unsigned n_pdu_total;
1181 int params;
1183 params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
1185 assert(is_varlen && is_string && !is_union);
1186 assert(params == NDR_F_NONE);
1188 /* string header for this: size_is first_is length_is */
1189 n_hdr = 12;
1191 /* fixed part -- exactly none of these */
1192 n_fixed = 0;
1194 if (!ndr_outer_grow(outer_ref, n_hdr))
1195 return (0); /* error already set */
1197 switch (nds->m_op) {
1198 case NDR_M_OP_MARSHALL:
1199 valp = outer_ref->datum;
1200 if (!valp) {
1201 NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
1202 return (0);
1205 if (outer_ref->backptr)
1206 assert(valp == *outer_ref->backptr);
1208 if (ti == &ndt_s_wchar) {
1210 * size_is is the number of characters in the
1211 * (multibyte) string, including the null.
1212 * In other words, symbols, not bytes.
1214 size_t wlen;
1215 wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
1216 if (wlen == (size_t)-1) {
1217 /* illegal sequence error? */
1218 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1219 return (0);
1221 if ((nds->flags & NDS_F_NONULL) == 0)
1222 wlen++;
1223 if (wlen > NDR_STRING_MAX) {
1224 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1225 return (0);
1227 size_is = wlen;
1228 } else {
1229 valp = outer_ref->datum;
1230 n_zeroes = 0;
1231 for (ix = 0; ix < NDR_STRING_MAX; ix++) {
1232 if (valp[ix] == 0) {
1233 n_zeroes++;
1234 if (n_zeroes >= is_varlen &&
1235 ix % is_varlen == 0) {
1236 break;
1238 } else {
1239 n_zeroes = 0;
1242 if (ix >= NDR_STRING_MAX) {
1243 NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
1244 return (0);
1246 size_is = ix+1;
1249 first_is = 0;
1251 if (nds->flags & NDS_F_NOTERM)
1252 length_is = size_is - 1;
1253 else
1254 length_is = size_is;
1256 if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
1257 !ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
1258 !ndr_outer_poke_sizing(outer_ref, 8, &length_is))
1259 return (0); /* error already set */
1260 break;
1262 case NDR_M_OP_UNMARSHALL:
1263 if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
1264 !ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
1265 !ndr_outer_peek_sizing(outer_ref, 8, &length_is))
1266 return (0); /* error already set */
1269 * In addition to the first_is check, we used to check that
1270 * size_is or size_is-1 was equal to length_is but Windows95
1271 * doesn't conform to this "rule" (see variable part below).
1272 * The srvmgr tool for Windows95 sent the following values
1273 * for a path string:
1275 * size_is = 261 (0x105)
1276 * first_is = 0
1277 * length_is = 53 (0x35)
1279 * The length_is was correct (for the given path) but the
1280 * size_is was the maximum path length rather than being
1281 * related to length_is.
1283 if (first_is != 0) {
1284 NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
1285 return (0);
1288 if (ti == &ndt_s_wchar) {
1290 * Decoding Unicode to UTF-8; we need to allow
1291 * for the maximum possible char size. It would
1292 * be nice to use mbequiv_strlen but the string
1293 * may not be null terminated.
1295 n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
1296 } else {
1297 n_alloc = (size_is + 1) * is_varlen;
1300 valp = NDS_MALLOC(nds, n_alloc, outer_ref);
1301 if (!valp) {
1302 NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
1303 return (0);
1306 bzero(valp, (size_is+1) * is_varlen);
1308 if (outer_ref->backptr)
1309 *outer_ref->backptr = valp;
1310 outer_ref->datum = valp;
1311 break;
1313 default:
1314 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1315 return (0);
1319 * Variable part - exactly length_is of these.
1321 * Usually, length_is is same as size_is and includes nul.
1322 * Some protocols use length_is = size_is-1, and length_is does
1323 * not include the nul (which is more consistent with DCE spec).
1324 * If the length_is is 0, there is no data following the
1325 * sizing header, regardless of size_is.
1327 n_variable = length_is * is_varlen;
1329 /* sum them up to determine the PDU space required */
1330 n_pdu_total = n_hdr + n_fixed + n_variable;
1332 /* similar sum to determine how much local memory is required */
1333 n_alloc = n_fixed + n_variable;
1335 rc = ndr_outer_grow(outer_ref, n_pdu_total);
1336 if (!rc)
1337 return (rc); /* error already set */
1339 if (length_is > 0) {
1340 bzero(&myref, sizeof (myref));
1341 myref.stream = nds;
1342 myref.enclosing = outer_ref;
1343 myref.ti = outer_ref->ti;
1344 myref.datum = outer_ref->datum;
1345 myref.name = "OUTER-STRING";
1346 myref.outer_flags = NDR_F_IS_STRING;
1347 myref.inner_flags = NDR_F_NONE;
1350 * Set up size_is and strlen_is for ndr_s_wchar.
1352 myref.size_is = size_is;
1353 myref.strlen_is = length_is;
1356 myref.pdu_offset = outer_ref->pdu_offset + 12;
1359 * Don't try to decode empty strings.
1361 if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
1362 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1363 return (1);
1366 if ((size_is != 0) && (length_is != 0)) {
1367 rc = ndr_inner(&myref);
1368 if (!rc)
1369 return (rc); /* error already set */
1372 nds->pdu_scan_offset = outer_ref->pdu_end_offset;
1373 return (1);
1377 ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
1378 unsigned long *sizing_p)
1380 ndr_stream_t *nds = outer_ref->stream;
1381 unsigned long pdu_offset;
1382 int rc;
1384 pdu_offset = outer_ref->pdu_offset + offset;
1386 if (pdu_offset < nds->outer_current->pdu_offset ||
1387 pdu_offset > nds->outer_current->pdu_end_offset ||
1388 pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1389 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1390 return (0);
1393 switch (nds->m_op) {
1394 case NDR_M_OP_MARSHALL:
1395 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1396 return (0);
1398 case NDR_M_OP_UNMARSHALL:
1399 rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1400 nds->swap, outer_ref);
1401 break;
1403 default:
1404 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1405 return (0);
1408 return (rc);
1412 ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
1413 unsigned long *sizing_p)
1415 ndr_stream_t *nds = outer_ref->stream;
1416 unsigned long pdu_offset;
1417 int rc;
1419 pdu_offset = outer_ref->pdu_offset + offset;
1421 if (pdu_offset < nds->outer_current->pdu_offset ||
1422 pdu_offset > nds->outer_current->pdu_end_offset ||
1423 pdu_offset+4 > nds->outer_current->pdu_end_offset) {
1424 NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
1425 return (0);
1428 switch (nds->m_op) {
1429 case NDR_M_OP_MARSHALL:
1430 rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
1431 nds->swap, outer_ref);
1432 break;
1434 case NDR_M_OP_UNMARSHALL:
1435 NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
1436 return (0);
1438 default:
1439 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1440 return (0);
1443 return (rc);
1447 * All OUTER constructs begin on a mod4 (dword) boundary - except
1448 * for the ones that don't: some MSRPC calls appear to use word or
1449 * packed alignment. Strings appear to be dword aligned.
1452 ndr_outer_align(ndr_ref_t *outer_ref)
1454 ndr_stream_t *nds = outer_ref->stream;
1455 int rc;
1456 unsigned n_pad;
1457 unsigned align;
1459 if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
1460 align = outer_ref->ti->alignment;
1461 n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
1462 } else {
1463 n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
1466 if (n_pad == 0)
1467 return (1); /* already aligned, often the case */
1469 if (!ndr_outer_grow(outer_ref, n_pad))
1470 return (0); /* error already set */
1472 switch (nds->m_op) {
1473 case NDR_M_OP_MARSHALL:
1474 rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
1475 if (!rc) {
1476 NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
1477 return (0);
1479 break;
1481 case NDR_M_OP_UNMARSHALL:
1482 break;
1484 default:
1485 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1486 return (0);
1489 nds->pdu_scan_offset += n_pad;
1490 return (1);
1494 ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
1496 ndr_stream_t *nds = outer_ref->stream;
1497 unsigned long pdu_want_size;
1498 int rc, is_ok = 0;
1500 pdu_want_size = nds->pdu_scan_offset + n_total;
1502 if (pdu_want_size <= nds->pdu_max_size) {
1503 is_ok = 1;
1506 switch (nds->m_op) {
1507 case NDR_M_OP_MARSHALL:
1508 if (is_ok)
1509 break;
1510 rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
1511 if (!rc) {
1512 NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
1513 return (0);
1515 break;
1517 case NDR_M_OP_UNMARSHALL:
1518 if (is_ok)
1519 break;
1520 NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
1521 return (0);
1523 default:
1524 NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
1525 return (0);
1528 if (nds->pdu_size < pdu_want_size)
1529 nds->pdu_size = pdu_want_size;
1531 outer_ref->pdu_end_offset = pdu_want_size;
1532 return (1);
1536 * INNER ELEMENTS
1538 * The local datum (arg_ref->datum) already exists, there is no need to
1539 * malloc() it. The datum should point at a member of a structure.
1541 * For the most part, ndr_inner() and its helpers are just a sanity
1542 * check. The underlying ti->ndr_func() could be called immediately
1543 * for non-pointer elements. For the sake of robustness, we detect
1544 * run-time errors here. Most of the situations this protects against
1545 * have already been checked by the IDL compiler. This is also a
1546 * common point for processing of all data, and so is a convenient
1547 * place to work from for debugging.
1550 ndr_inner(ndr_ref_t *arg_ref)
1552 ndr_typeinfo_t *ti = arg_ref->ti;
1553 int is_varlen = ti->pdu_size_variable_part;
1554 int is_union = NDR_IS_UNION(ti);
1555 int error = NDR_ERR_INNER_PARAMS_BAD;
1556 int params;
1558 params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1560 switch (params) {
1561 case NDR_F_NONE:
1562 if (is_union) {
1563 error = NDR_ERR_SWITCH_VALUE_MISSING;
1564 break;
1566 return (*ti->ndr_func)(arg_ref);
1568 case NDR_F_SIZE_IS:
1569 case NDR_F_DIMENSION_IS:
1570 case NDR_F_IS_POINTER+NDR_F_SIZE_IS: /* pointer to something */
1571 case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS: /* pointer to something */
1572 if (is_varlen) {
1573 error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
1574 break;
1576 if (is_union) {
1577 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1578 break;
1580 if (params & NDR_F_IS_POINTER)
1581 return (ndr_inner_pointer(arg_ref));
1582 else if (params & NDR_F_IS_REFERENCE)
1583 return (ndr_inner_reference(arg_ref));
1584 else
1585 return (ndr_inner_array(arg_ref));
1587 case NDR_F_IS_POINTER: /* type is pointer to one something */
1588 if (is_union) {
1589 error = NDR_ERR_ARRAY_UNION_ILLEGAL;
1590 break;
1592 return (ndr_inner_pointer(arg_ref));
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;
1599 return (ndr_inner_reference(arg_ref));
1601 case NDR_F_SWITCH_IS:
1602 if (!is_union) {
1603 error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
1604 break;
1606 return (*ti->ndr_func)(arg_ref);
1608 default:
1609 error = NDR_ERR_INNER_PARAMS_BAD;
1610 break;
1614 * If we get here, something is wrong. Most likely,
1615 * the params flags do not match
1617 NDR_SET_ERROR(arg_ref, error);
1618 return (0);
1622 ndr_inner_pointer(ndr_ref_t *arg_ref)
1624 ndr_stream_t *nds = arg_ref->stream;
1625 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1626 char **valpp = (char **)arg_ref->datum;
1627 ndr_ref_t *outer_ref;
1629 if (!ndr__ulong(arg_ref))
1630 return (0); /* error */
1631 if (!*valpp)
1632 return (1); /* NULL pointer */
1634 outer_ref = ndr_enter_outer_queue(arg_ref);
1635 if (!outer_ref)
1636 return (0); /* error already set */
1639 * Move advice in inner_flags to outer_flags.
1640 * Retain pointer flag for conformant arrays.
1642 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1643 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1644 outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
1645 #ifdef NDR_INNER_PTR_NOT_YET
1646 outer_ref->outer_flags |= NDR_F_BACKPTR;
1647 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1648 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1650 #endif /* NDR_INNER_PTR_NOT_YET */
1652 outer_ref->backptr = valpp;
1654 switch (nds->m_op) {
1655 case NDR_M_OP_MARSHALL:
1656 outer_ref->datum = *valpp;
1657 break;
1659 case NDR_M_OP_UNMARSHALL:
1661 * This is probably wrong if the application allocated
1662 * memory in advance. Indicate no value for now.
1663 * ONC RPC handles this case.
1665 *valpp = 0;
1666 outer_ref->datum = 0;
1667 break;
1670 return (1); /* pointer dereference scheduled */
1674 ndr_inner_reference(ndr_ref_t *arg_ref)
1676 ndr_stream_t *nds = arg_ref->stream;
1677 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1678 char **valpp = (char **)arg_ref->datum;
1679 ndr_ref_t *outer_ref;
1681 outer_ref = ndr_enter_outer_queue(arg_ref);
1682 if (!outer_ref)
1683 return (0); /* error already set */
1686 * Move advice in inner_flags to outer_flags.
1687 * Retain reference flag for conformant arrays.
1689 outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
1690 if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
1691 outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
1692 #ifdef NDR_INNER_REF_NOT_YET
1693 outer_ref->outer_flags |= NDR_F_BACKPTR;
1694 if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
1695 outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
1697 #endif /* NDR_INNER_REF_NOT_YET */
1699 outer_ref->backptr = valpp;
1701 switch (nds->m_op) {
1702 case NDR_M_OP_MARSHALL:
1703 outer_ref->datum = *valpp;
1704 break;
1706 case NDR_M_OP_UNMARSHALL:
1708 * This is probably wrong if the application allocated
1709 * memory in advance. Indicate no value for now.
1710 * ONC RPC handles this case.
1712 *valpp = 0;
1713 outer_ref->datum = 0;
1714 break;
1717 return (1); /* pointer dereference scheduled */
1721 ndr_inner_array(ndr_ref_t *encl_ref)
1723 ndr_typeinfo_t *ti = encl_ref->ti;
1724 ndr_ref_t myref;
1725 unsigned long pdu_offset = encl_ref->pdu_offset;
1726 unsigned long n_elem;
1727 unsigned long i;
1728 char name[30];
1730 if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
1731 /* now is the time to check/set size */
1732 if (!ndr_size_is(encl_ref))
1733 return (0); /* error already set */
1734 n_elem = encl_ref->size_is;
1735 } else {
1736 assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
1737 n_elem = encl_ref->dimension_is;
1740 bzero(&myref, sizeof (myref));
1741 myref.enclosing = encl_ref;
1742 myref.stream = encl_ref->stream;
1743 myref.packed_alignment = 0;
1744 myref.ti = ti;
1745 myref.inner_flags = NDR_F_NONE;
1747 for (i = 0; i < n_elem; i++) {
1748 (void) snprintf(name, sizeof (name), "[%lu]", i);
1749 myref.name = name;
1750 myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
1751 myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
1753 if (!ndr_inner(&myref))
1754 return (0);
1757 return (1);
1762 * BASIC TYPES
1764 #define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1765 extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
1766 ndr_typeinfo_t ndt_##TYPE = { \
1767 1, /* NDR version */ \
1768 (SIZE)-1, /* alignment */ \
1769 NDR_F_NONE, /* flags */ \
1770 ndr_##TYPE, /* ndr_func */ \
1771 SIZE, /* pdu_size_fixed_part */ \
1772 0, /* pdu_size_variable_part */ \
1773 SIZE, /* c_size_fixed_part */ \
1774 0, /* c_size_variable_part */ \
1775 }; \
1776 int ndr_##TYPE(struct ndr_reference *ref) { \
1777 return (ndr_basic_integer(ref, SIZE)); \
1780 #define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
1781 extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
1782 ndr_typeinfo_t ndt_s##TYPE = { \
1783 1, /* NDR version */ \
1784 (SIZE)-1, /* alignment */ \
1785 NDR_F_STRING, /* flags */ \
1786 ndr_s##TYPE, /* ndr_func */ \
1787 0, /* pdu_size_fixed_part */ \
1788 SIZE, /* pdu_size_variable_part */ \
1789 0, /* c_size_fixed_part */ \
1790 SIZE, /* c_size_variable_part */ \
1791 }; \
1792 int ndr_s##TYPE(struct ndr_reference *ref) { \
1793 return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
1796 #define MAKE_BASIC_TYPE(TYPE, SIZE) \
1797 MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
1798 MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
1800 int ndr_basic_integer(ndr_ref_t *, unsigned);
1801 int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
1803 /* Comments to be nice to those searching for these types. */
1804 MAKE_BASIC_TYPE(_char, 1) /* ndt__char, ndt_s_char */
1805 MAKE_BASIC_TYPE(_uchar, 1) /* ndt__uchar, ndt_s_uchar */
1806 MAKE_BASIC_TYPE(_short, 2) /* ndt__short, ndt_s_short */
1807 MAKE_BASIC_TYPE(_ushort, 2) /* ndt__ushort, ndt_s_ushort */
1808 MAKE_BASIC_TYPE(_long, 4) /* ndt__long, ndt_s_long */
1809 MAKE_BASIC_TYPE(_ulong, 4) /* ndt__ulong, ndt_s_ulong */
1811 MAKE_BASIC_TYPE_BASE(_wchar, 2) /* ndt__wchar, ndt_s_wchar */
1814 ndr_basic_integer(ndr_ref_t *ref, unsigned size)
1816 ndr_stream_t *nds = ref->stream;
1817 char *valp = (char *)ref->datum;
1818 int rc;
1820 switch (nds->m_op) {
1821 case NDR_M_OP_MARSHALL:
1822 rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
1823 valp, nds->swap, ref);
1824 break;
1826 case NDR_M_OP_UNMARSHALL:
1827 rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
1828 valp, nds->swap, ref);
1829 break;
1831 default:
1832 NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
1833 return (0);
1836 return (rc);
1840 ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
1842 unsigned long pdu_offset = encl_ref->pdu_offset;
1843 unsigned size = type_under->pdu_size_fixed_part;
1844 char *valp;
1845 ndr_ref_t myref;
1846 unsigned long i;
1847 long sense = 0;
1848 char name[30];
1850 assert(size != 0);
1852 bzero(&myref, sizeof (myref));
1853 myref.enclosing = encl_ref;
1854 myref.stream = encl_ref->stream;
1855 myref.packed_alignment = 0;
1856 myref.ti = type_under;
1857 myref.inner_flags = NDR_F_NONE;
1858 myref.name = name;
1860 for (i = 0; i < NDR_STRING_MAX; i++) {
1861 (void) snprintf(name, sizeof (name), "[%lu]", i);
1862 myref.pdu_offset = pdu_offset + i * size;
1863 valp = encl_ref->datum + i * size;
1864 myref.datum = valp;
1866 if (!ndr_inner(&myref))
1867 return (0);
1869 switch (size) {
1870 case 1: sense = *valp; break;
1871 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1872 case 2: sense = *(short *)valp; break;
1873 /*LINTED E_BAD_PTR_CAST_ALIGN*/
1874 case 4: sense = *(long *)valp; break;
1877 if (!sense)
1878 break;
1881 return (1);
1885 extern int ndr_s_wchar(ndr_ref_t *encl_ref);
1886 ndr_typeinfo_t ndt_s_wchar = {
1887 1, /* NDR version */
1888 2-1, /* alignment */
1889 NDR_F_STRING, /* flags */
1890 ndr_s_wchar, /* ndr_func */
1891 0, /* pdu_size_fixed_part */
1892 2, /* pdu_size_variable_part */
1893 0, /* c_size_fixed_part */
1894 1, /* c_size_variable_part */
1899 * Hand coded wchar function because all strings are transported
1900 * as wide characters. During NDR_M_OP_MARSHALL, we convert from
1901 * multi-byte to wide characters. During NDR_M_OP_UNMARSHALL, we
1902 * convert from wide characters to multi-byte.
1904 * The most critical thing to get right in this function is to
1905 * marshall or unmarshall _exactly_ the number of elements the
1906 * OtW length specifies, as saved by the caller in: strlen_is.
1907 * Doing otherwise would leave us positioned at the wrong place
1908 * in the data stream for whatever follows this. Note that the
1909 * string data covered by strlen_is may or may not include any
1910 * null termination, but the converted string provided by the
1911 * caller or returned always has a null terminator.
1914 ndr_s_wchar(ndr_ref_t *encl_ref)
1916 ndr_stream_t *nds = encl_ref->stream;
1917 char *valp = encl_ref->datum;
1918 ndr_ref_t myref;
1919 char name[30];
1920 ndr_wchar_t wcs[NDR_STRING_MAX+1];
1921 size_t i, slen, wlen;
1923 /* This is enforced in ndr_outer_string() */
1924 assert(encl_ref->strlen_is <= NDR_STRING_MAX);
1926 if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1928 * To avoid problems with zero length strings
1929 * we can just null terminate here and be done.
1931 if (encl_ref->strlen_is == 0) {
1932 encl_ref->datum[0] = '\0';
1933 return (1);
1938 * If we're marshalling, convert the given string
1939 * from UTF-8 into a local UCS-2 string.
1941 if (nds->m_op == NDR_M_OP_MARSHALL) {
1942 wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
1943 if (wlen == (size_t)-1)
1944 return (0);
1946 * Add a nulls to make strlen_is.
1947 * (always zero or one of them)
1948 * Then null terminate at wlen,
1949 * just for debug convenience.
1951 while (wlen < encl_ref->strlen_is)
1952 wcs[wlen++] = 0;
1953 wcs[wlen] = 0;
1957 * Copy wire data to or from the local wc string.
1958 * Always exactly strlen_is elements.
1960 bzero(&myref, sizeof (myref));
1961 myref.enclosing = encl_ref;
1962 myref.stream = encl_ref->stream;
1963 myref.packed_alignment = 0;
1964 myref.ti = &ndt__wchar;
1965 myref.inner_flags = NDR_F_NONE;
1966 myref.name = name;
1967 myref.pdu_offset = encl_ref->pdu_offset;
1968 myref.datum = (char *)wcs;
1969 wlen = encl_ref->strlen_is;
1971 for (i = 0; i < wlen; i++) {
1972 (void) snprintf(name, sizeof (name), "[%lu]", i);
1973 if (!ndr_inner(&myref))
1974 return (0);
1975 myref.pdu_offset += sizeof (ndr_wchar_t);
1976 myref.datum += sizeof (ndr_wchar_t);
1980 * If this is unmarshall, convert the local UCS-2 string
1981 * into a UTF-8 string in the caller's buffer. The caller
1982 * previously determined the space required and provides a
1983 * buffer of sufficient size.
1985 if (nds->m_op == NDR_M_OP_UNMARSHALL) {
1986 wcs[wlen] = 0;
1987 slen = ndr__wcstombs(valp, wcs, wlen);
1988 if (slen == (size_t)-1)
1989 return (0);
1990 valp[slen] = '\0';
1993 return (1);
1997 * Converts a multibyte character string to a little-endian, wide-char
1998 * string. No more than nwchars wide characters are stored.
1999 * A terminating null wide character is appended if there is room.
2001 * Returns the number of wide characters converted, not counting
2002 * any terminating null wide character. Returns -1 if an invalid
2003 * multibyte character is encountered.
2005 /* ARGSUSED */
2006 size_t
2007 ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
2008 size_t nwchars)
2010 size_t len;
2012 #ifdef _BIG_ENDIAN
2013 if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
2014 /* Make WC string in LE order. */
2015 len = ndr__mbstowcs_le(wcs, mbs, nwchars);
2016 } else
2017 #endif
2018 len = ndr__mbstowcs(wcs, mbs, nwchars);
2020 return (len);