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