1 | /* |
2 | * xdr.c, Generic XDR routines implementation. |
3 | * |
4 | * Copyright (c) 2010, Oracle America, Inc. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are |
8 | * met: |
9 | * |
10 | * * Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * * Redistributions in binary form must reproduce the above |
13 | * copyright notice, this list of conditions and the following |
14 | * disclaimer in the documentation and/or other materials |
15 | * provided with the distribution. |
16 | * * Neither the name of the "Oracle America, Inc." nor the names of its |
17 | * contributors may be used to endorse or promote products derived |
18 | * from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
24 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
27 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | * |
33 | * These are the "generic" xdr routines used to serialize and de-serialize |
34 | * most common data items. See xdr.h for more info on the interface to |
35 | * xdr. |
36 | */ |
37 | |
38 | #include <stdio.h> |
39 | #include <limits.h> |
40 | #include <string.h> |
41 | #include <libintl.h> |
42 | #include <wchar.h> |
43 | #include <stdint.h> |
44 | |
45 | #include <rpc/types.h> |
46 | #include <rpc/xdr.h> |
47 | #include <shlib-compat.h> |
48 | |
49 | |
50 | /* |
51 | * constants specific to the xdr "protocol" |
52 | */ |
53 | #define XDR_FALSE ((long) 0) |
54 | #define XDR_TRUE ((long) 1) |
55 | #define LASTUNSIGNED ((u_int) 0-1) |
56 | |
57 | /* |
58 | * for unit alignment |
59 | */ |
60 | static const char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0}; |
61 | |
62 | /* |
63 | * Free a data structure using XDR |
64 | * Not a filter, but a convenient utility nonetheless |
65 | */ |
66 | void |
67 | xdr_free (xdrproc_t proc, char *objp) |
68 | { |
69 | XDR x; |
70 | |
71 | x.x_op = XDR_FREE; |
72 | (*proc) (&x, objp); |
73 | } |
74 | #ifdef EXPORT_RPC_SYMBOLS |
75 | libc_hidden_def (xdr_free) |
76 | #else |
77 | libc_hidden_nolink_sunrpc (xdr_free, GLIBC_2_0) |
78 | #endif |
79 | |
80 | /* |
81 | * XDR nothing |
82 | */ |
83 | bool_t |
84 | xdr_void (void) |
85 | { |
86 | return TRUE; |
87 | } |
88 | #ifdef EXPORT_RPC_SYMBOLS |
89 | libc_hidden_def (xdr_void) |
90 | #else |
91 | libc_hidden_nolink_sunrpc (xdr_void, GLIBC_2_0) |
92 | #endif |
93 | |
94 | /* |
95 | * XDR integers |
96 | */ |
97 | bool_t |
98 | xdr_int (XDR *xdrs, int *ip) |
99 | { |
100 | |
101 | #if INT_MAX < LONG_MAX |
102 | long l; |
103 | |
104 | switch (xdrs->x_op) |
105 | { |
106 | case XDR_ENCODE: |
107 | l = (long) *ip; |
108 | return XDR_PUTLONG (xdrs, &l); |
109 | |
110 | case XDR_DECODE: |
111 | if (!XDR_GETLONG (xdrs, &l)) |
112 | { |
113 | return FALSE; |
114 | } |
115 | *ip = (int) l; |
116 | /* Fall through. */ |
117 | case XDR_FREE: |
118 | return TRUE; |
119 | } |
120 | return FALSE; |
121 | #elif INT_MAX == LONG_MAX |
122 | return xdr_long (xdrs, (long *) ip); |
123 | #elif INT_MAX == SHRT_MAX |
124 | return xdr_short (xdrs, (short *) ip); |
125 | #else |
126 | #error unexpected integer sizes in_xdr_int() |
127 | #endif |
128 | } |
129 | #ifdef EXPORT_RPC_SYMBOLS |
130 | libc_hidden_def (xdr_int) |
131 | #else |
132 | libc_hidden_nolink_sunrpc (xdr_int, GLIBC_2_0) |
133 | #endif |
134 | |
135 | /* |
136 | * XDR unsigned integers |
137 | */ |
138 | bool_t |
139 | xdr_u_int (XDR *xdrs, u_int *up) |
140 | { |
141 | #if UINT_MAX < ULONG_MAX |
142 | long l; |
143 | |
144 | switch (xdrs->x_op) |
145 | { |
146 | case XDR_ENCODE: |
147 | l = (u_long) * up; |
148 | return XDR_PUTLONG (xdrs, &l); |
149 | |
150 | case XDR_DECODE: |
151 | if (!XDR_GETLONG (xdrs, &l)) |
152 | { |
153 | return FALSE; |
154 | } |
155 | *up = (u_int) (u_long) l; |
156 | /* Fall through. */ |
157 | case XDR_FREE: |
158 | return TRUE; |
159 | } |
160 | return FALSE; |
161 | #elif UINT_MAX == ULONG_MAX |
162 | return xdr_u_long (xdrs, (u_long *) up); |
163 | #elif UINT_MAX == USHRT_MAX |
164 | return xdr_short (xdrs, (short *) up); |
165 | #else |
166 | #error unexpected integer sizes in_xdr_u_int() |
167 | #endif |
168 | } |
169 | #ifdef EXPORT_RPC_SYMBOLS |
170 | libc_hidden_def (xdr_u_int) |
171 | #else |
172 | libc_hidden_nolink_sunrpc (xdr_u_int, GLIBC_2_0) |
173 | #endif |
174 | |
175 | /* |
176 | * XDR long integers |
177 | * The definition of xdr_long() is kept for backward |
178 | * compatibility. Instead xdr_int() should be used. |
179 | */ |
180 | bool_t |
181 | xdr_long (XDR *xdrs, long *lp) |
182 | { |
183 | |
184 | if (xdrs->x_op == XDR_ENCODE |
185 | && (sizeof (int32_t) == sizeof (long) |
186 | || (int32_t) *lp == *lp)) |
187 | return XDR_PUTLONG (xdrs, lp); |
188 | |
189 | if (xdrs->x_op == XDR_DECODE) |
190 | return XDR_GETLONG (xdrs, lp); |
191 | |
192 | if (xdrs->x_op == XDR_FREE) |
193 | return TRUE; |
194 | |
195 | return FALSE; |
196 | } |
197 | #ifdef EXPORT_RPC_SYMBOLS |
198 | libc_hidden_def (xdr_long) |
199 | #else |
200 | libc_hidden_nolink_sunrpc (xdr_long, GLIBC_2_0) |
201 | #endif |
202 | |
203 | /* |
204 | * XDR unsigned long integers |
205 | * The definition of xdr_u_long() is kept for backward |
206 | * compatibility. Instead xdr_u_int() should be used. |
207 | */ |
208 | bool_t |
209 | xdr_u_long (XDR *xdrs, u_long *ulp) |
210 | { |
211 | switch (xdrs->x_op) |
212 | { |
213 | case XDR_DECODE: |
214 | { |
215 | long int tmp; |
216 | |
217 | if (XDR_GETLONG (xdrs, &tmp) == FALSE) |
218 | return FALSE; |
219 | |
220 | *ulp = (uint32_t) tmp; |
221 | return TRUE; |
222 | } |
223 | |
224 | case XDR_ENCODE: |
225 | if (sizeof (uint32_t) != sizeof (u_long) |
226 | && (uint32_t) *ulp != *ulp) |
227 | return FALSE; |
228 | |
229 | return XDR_PUTLONG (xdrs, (long *) ulp); |
230 | |
231 | case XDR_FREE: |
232 | return TRUE; |
233 | } |
234 | return FALSE; |
235 | } |
236 | #ifdef EXPORT_RPC_SYMBOLS |
237 | libc_hidden_def (xdr_u_long) |
238 | #else |
239 | libc_hidden_nolink_sunrpc (xdr_u_long, GLIBC_2_0) |
240 | #endif |
241 | |
242 | /* |
243 | * XDR hyper integers |
244 | * same as xdr_u_hyper - open coded to save a proc call! |
245 | */ |
246 | bool_t |
247 | xdr_hyper (XDR *xdrs, quad_t *llp) |
248 | { |
249 | long int t1, t2; |
250 | |
251 | if (xdrs->x_op == XDR_ENCODE) |
252 | { |
253 | t1 = (long) ((*llp) >> 32); |
254 | t2 = (long) (*llp); |
255 | return (XDR_PUTLONG(xdrs, &t1) && XDR_PUTLONG(xdrs, &t2)); |
256 | } |
257 | |
258 | if (xdrs->x_op == XDR_DECODE) |
259 | { |
260 | if (!XDR_GETLONG(xdrs, &t1) || !XDR_GETLONG(xdrs, &t2)) |
261 | return FALSE; |
262 | *llp = ((quad_t) t1) << 32; |
263 | *llp |= (uint32_t) t2; |
264 | return TRUE; |
265 | } |
266 | |
267 | if (xdrs->x_op == XDR_FREE) |
268 | return TRUE; |
269 | |
270 | return FALSE; |
271 | } |
272 | #ifdef EXPORT_RPC_SYMBOLS |
273 | libc_hidden_def (xdr_hyper) |
274 | #else |
275 | libc_hidden_nolink_sunrpc (xdr_hyper, GLIBC_2_1_1) |
276 | #endif |
277 | |
278 | /* |
279 | * XDR hyper integers |
280 | * same as xdr_hyper - open coded to save a proc call! |
281 | */ |
282 | bool_t |
283 | xdr_u_hyper (XDR *xdrs, u_quad_t *ullp) |
284 | { |
285 | long int t1, t2; |
286 | |
287 | if (xdrs->x_op == XDR_ENCODE) |
288 | { |
289 | t1 = (unsigned long) ((*ullp) >> 32); |
290 | t2 = (unsigned long) (*ullp); |
291 | return (XDR_PUTLONG(xdrs, &t1) && XDR_PUTLONG(xdrs, &t2)); |
292 | } |
293 | |
294 | if (xdrs->x_op == XDR_DECODE) |
295 | { |
296 | if (!XDR_GETLONG(xdrs, &t1) || !XDR_GETLONG(xdrs, &t2)) |
297 | return FALSE; |
298 | *ullp = ((u_quad_t) t1) << 32; |
299 | *ullp |= (uint32_t) t2; |
300 | return TRUE; |
301 | } |
302 | |
303 | if (xdrs->x_op == XDR_FREE) |
304 | return TRUE; |
305 | |
306 | return FALSE; |
307 | } |
308 | #ifdef EXPORT_RPC_SYMBOLS |
309 | libc_hidden_def (xdr_u_hyper) |
310 | #else |
311 | libc_hidden_nolink_sunrpc (xdr_u_hyper, GLIBC_2_1_1) |
312 | #endif |
313 | |
314 | bool_t |
315 | xdr_longlong_t (XDR *xdrs, quad_t *llp) |
316 | { |
317 | return xdr_hyper (xdrs, llp); |
318 | } |
319 | #ifdef EXPORT_RPC_SYMBOLS |
320 | libc_hidden_def (xdr_longlong_t) |
321 | #else |
322 | libc_hidden_nolink_sunrpc (xdr_longlong_t, GLIBC_2_1_1) |
323 | #endif |
324 | |
325 | bool_t |
326 | xdr_u_longlong_t (XDR *xdrs, u_quad_t *ullp) |
327 | { |
328 | return xdr_u_hyper (xdrs, ullp); |
329 | } |
330 | #ifdef EXPORT_RPC_SYMBOLS |
331 | libc_hidden_def (xdr_u_longlong_t) |
332 | #else |
333 | libc_hidden_nolink_sunrpc (xdr_u_longlong_t, GLIBC_2_1_1) |
334 | #endif |
335 | |
336 | /* |
337 | * XDR short integers |
338 | */ |
339 | bool_t |
340 | xdr_short (XDR *xdrs, short *sp) |
341 | { |
342 | long l; |
343 | |
344 | switch (xdrs->x_op) |
345 | { |
346 | case XDR_ENCODE: |
347 | l = (long) *sp; |
348 | return XDR_PUTLONG (xdrs, &l); |
349 | |
350 | case XDR_DECODE: |
351 | if (!XDR_GETLONG (xdrs, &l)) |
352 | { |
353 | return FALSE; |
354 | } |
355 | *sp = (short) l; |
356 | return TRUE; |
357 | |
358 | case XDR_FREE: |
359 | return TRUE; |
360 | } |
361 | return FALSE; |
362 | } |
363 | #ifdef EXPORT_RPC_SYMBOLS |
364 | libc_hidden_def (xdr_short) |
365 | #else |
366 | libc_hidden_nolink_sunrpc (xdr_short, GLIBC_2_0) |
367 | #endif |
368 | |
369 | /* |
370 | * XDR unsigned short integers |
371 | */ |
372 | bool_t |
373 | xdr_u_short (XDR *xdrs, u_short *usp) |
374 | { |
375 | long l; |
376 | |
377 | switch (xdrs->x_op) |
378 | { |
379 | case XDR_ENCODE: |
380 | l = (u_long) * usp; |
381 | return XDR_PUTLONG (xdrs, &l); |
382 | |
383 | case XDR_DECODE: |
384 | if (!XDR_GETLONG (xdrs, &l)) |
385 | { |
386 | return FALSE; |
387 | } |
388 | *usp = (u_short) (u_long) l; |
389 | return TRUE; |
390 | |
391 | case XDR_FREE: |
392 | return TRUE; |
393 | } |
394 | return FALSE; |
395 | } |
396 | #ifdef EXPORT_RPC_SYMBOLS |
397 | libc_hidden_def (xdr_u_short) |
398 | #else |
399 | libc_hidden_nolink_sunrpc (xdr_u_short, GLIBC_2_0) |
400 | #endif |
401 | |
402 | |
403 | /* |
404 | * XDR a char |
405 | */ |
406 | bool_t |
407 | xdr_char (XDR *xdrs, char *cp) |
408 | { |
409 | int i; |
410 | |
411 | i = (*cp); |
412 | if (!xdr_int (xdrs, &i)) |
413 | { |
414 | return FALSE; |
415 | } |
416 | *cp = i; |
417 | return TRUE; |
418 | } |
419 | #ifdef EXPORT_RPC_SYMBOLS |
420 | libc_hidden_def (xdr_char) |
421 | #else |
422 | libc_hidden_nolink_sunrpc (xdr_char, GLIBC_2_0) |
423 | #endif |
424 | |
425 | /* |
426 | * XDR an unsigned char |
427 | */ |
428 | bool_t |
429 | xdr_u_char (XDR *xdrs, u_char *cp) |
430 | { |
431 | u_int u; |
432 | |
433 | u = (*cp); |
434 | if (!xdr_u_int (xdrs, &u)) |
435 | { |
436 | return FALSE; |
437 | } |
438 | *cp = u; |
439 | return TRUE; |
440 | } |
441 | #ifdef EXPORT_RPC_SYMBOLS |
442 | libc_hidden_def (xdr_u_char) |
443 | #else |
444 | libc_hidden_nolink_sunrpc (xdr_u_char, GLIBC_2_0) |
445 | #endif |
446 | |
447 | /* |
448 | * XDR booleans |
449 | */ |
450 | bool_t |
451 | xdr_bool (XDR *xdrs, bool_t *bp) |
452 | { |
453 | long lb; |
454 | |
455 | switch (xdrs->x_op) |
456 | { |
457 | case XDR_ENCODE: |
458 | lb = *bp ? XDR_TRUE : XDR_FALSE; |
459 | return XDR_PUTLONG (xdrs, &lb); |
460 | |
461 | case XDR_DECODE: |
462 | if (!XDR_GETLONG (xdrs, &lb)) |
463 | { |
464 | return FALSE; |
465 | } |
466 | *bp = (lb == XDR_FALSE) ? FALSE : TRUE; |
467 | return TRUE; |
468 | |
469 | case XDR_FREE: |
470 | return TRUE; |
471 | } |
472 | return FALSE; |
473 | } |
474 | #ifdef EXPORT_RPC_SYMBOLS |
475 | libc_hidden_def (xdr_bool) |
476 | #else |
477 | libc_hidden_nolink_sunrpc (xdr_bool, GLIBC_2_0) |
478 | #endif |
479 | |
480 | /* |
481 | * XDR enumerations |
482 | */ |
483 | bool_t |
484 | xdr_enum (XDR *xdrs, enum_t *ep) |
485 | { |
486 | enum sizecheck |
487 | { |
488 | SIZEVAL |
489 | }; /* used to find the size of an enum */ |
490 | |
491 | /* |
492 | * enums are treated as ints |
493 | */ |
494 | if (sizeof (enum sizecheck) == 4) |
495 | { |
496 | #if INT_MAX < LONG_MAX |
497 | long l; |
498 | |
499 | switch (xdrs->x_op) |
500 | { |
501 | case XDR_ENCODE: |
502 | l = *ep; |
503 | return XDR_PUTLONG (xdrs, &l); |
504 | |
505 | case XDR_DECODE: |
506 | if (!XDR_GETLONG (xdrs, &l)) |
507 | { |
508 | return FALSE; |
509 | } |
510 | *ep = l; |
511 | /* Fall through. */ |
512 | case XDR_FREE: |
513 | return TRUE; |
514 | |
515 | } |
516 | return FALSE; |
517 | #else |
518 | return xdr_long (xdrs, (long *) ep); |
519 | #endif |
520 | } |
521 | else if (sizeof (enum sizecheck) == sizeof (short)) |
522 | { |
523 | return xdr_short (xdrs, (short *) ep); |
524 | } |
525 | else |
526 | { |
527 | return FALSE; |
528 | } |
529 | } |
530 | #ifdef EXPORT_RPC_SYMBOLS |
531 | libc_hidden_def (xdr_enum) |
532 | #else |
533 | libc_hidden_nolink_sunrpc (xdr_enum, GLIBC_2_0) |
534 | #endif |
535 | |
536 | /* |
537 | * XDR opaque data |
538 | * Allows the specification of a fixed size sequence of opaque bytes. |
539 | * cp points to the opaque object and cnt gives the byte length. |
540 | */ |
541 | bool_t |
542 | xdr_opaque (XDR *xdrs, caddr_t cp, u_int cnt) |
543 | { |
544 | u_int rndup; |
545 | static char crud[BYTES_PER_XDR_UNIT]; |
546 | |
547 | /* |
548 | * if no data we are done |
549 | */ |
550 | if (cnt == 0) |
551 | return TRUE; |
552 | |
553 | /* |
554 | * round byte count to full xdr units |
555 | */ |
556 | rndup = cnt % BYTES_PER_XDR_UNIT; |
557 | if (rndup > 0) |
558 | rndup = BYTES_PER_XDR_UNIT - rndup; |
559 | |
560 | switch (xdrs->x_op) |
561 | { |
562 | case XDR_DECODE: |
563 | if (!XDR_GETBYTES (xdrs, cp, cnt)) |
564 | { |
565 | return FALSE; |
566 | } |
567 | if (rndup == 0) |
568 | return TRUE; |
569 | return XDR_GETBYTES (xdrs, (caddr_t)crud, rndup); |
570 | |
571 | case XDR_ENCODE: |
572 | if (!XDR_PUTBYTES (xdrs, cp, cnt)) |
573 | { |
574 | return FALSE; |
575 | } |
576 | if (rndup == 0) |
577 | return TRUE; |
578 | return XDR_PUTBYTES (xdrs, xdr_zero, rndup); |
579 | |
580 | case XDR_FREE: |
581 | return TRUE; |
582 | } |
583 | return FALSE; |
584 | } |
585 | #ifdef EXPORT_RPC_SYMBOLS |
586 | libc_hidden_def (xdr_opaque) |
587 | #else |
588 | libc_hidden_nolink_sunrpc (xdr_opaque, GLIBC_2_0) |
589 | #endif |
590 | |
591 | /* |
592 | * XDR counted bytes |
593 | * *cpp is a pointer to the bytes, *sizep is the count. |
594 | * If *cpp is NULL maxsize bytes are allocated |
595 | */ |
596 | bool_t |
597 | xdr_bytes (XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize) |
598 | { |
599 | char *sp = *cpp; /* sp is the actual string pointer */ |
600 | u_int nodesize; |
601 | |
602 | /* |
603 | * first deal with the length since xdr bytes are counted |
604 | */ |
605 | if (!xdr_u_int (xdrs, sizep)) |
606 | { |
607 | return FALSE; |
608 | } |
609 | nodesize = *sizep; |
610 | if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) |
611 | { |
612 | return FALSE; |
613 | } |
614 | |
615 | /* |
616 | * now deal with the actual bytes |
617 | */ |
618 | switch (xdrs->x_op) |
619 | { |
620 | case XDR_DECODE: |
621 | if (nodesize == 0) |
622 | { |
623 | return TRUE; |
624 | } |
625 | if (sp == NULL) |
626 | { |
627 | *cpp = sp = (char *) mem_alloc (nodesize); |
628 | } |
629 | if (sp == NULL) |
630 | { |
631 | (void) __fxprintf (NULL, "%s: %s" , __func__, _("out of memory\n" )); |
632 | return FALSE; |
633 | } |
634 | /* Fall through. */ |
635 | |
636 | case XDR_ENCODE: |
637 | return xdr_opaque (xdrs, sp, nodesize); |
638 | |
639 | case XDR_FREE: |
640 | if (sp != NULL) |
641 | { |
642 | mem_free (sp, nodesize); |
643 | *cpp = NULL; |
644 | } |
645 | return TRUE; |
646 | } |
647 | return FALSE; |
648 | } |
649 | #ifdef EXPORT_RPC_SYMBOLS |
650 | libc_hidden_def (xdr_bytes) |
651 | #else |
652 | libc_hidden_nolink_sunrpc (xdr_bytes, GLIBC_2_0) |
653 | #endif |
654 | |
655 | /* |
656 | * Implemented here due to commonality of the object. |
657 | */ |
658 | bool_t |
659 | xdr_netobj (XDR *xdrs, struct netobj *np) |
660 | { |
661 | |
662 | return xdr_bytes (xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ); |
663 | } |
664 | #ifdef EXPORT_RPC_SYMBOLS |
665 | libc_hidden_def (xdr_netobj) |
666 | #else |
667 | libc_hidden_nolink_sunrpc (xdr_netobj, GLIBC_2_0) |
668 | #endif |
669 | |
670 | /* |
671 | * XDR a discriminated union |
672 | * Support routine for discriminated unions. |
673 | * You create an array of xdrdiscrim structures, terminated with |
674 | * an entry with a null procedure pointer. The routine gets |
675 | * the discriminant value and then searches the array of xdrdiscrims |
676 | * looking for that value. It calls the procedure given in the xdrdiscrim |
677 | * to handle the discriminant. If there is no specific routine a default |
678 | * routine may be called. |
679 | * If there is no specific or default routine an error is returned. |
680 | */ |
681 | bool_t |
682 | xdr_union (XDR *xdrs, |
683 | /* enum to decide which arm to work on */ |
684 | enum_t *dscmp, |
685 | /* the union itself */ |
686 | char *unp, |
687 | /* [value, xdr proc] for each arm */ |
688 | const struct xdr_discrim *choices, |
689 | /* default xdr routine */ |
690 | xdrproc_t dfault) |
691 | { |
692 | enum_t dscm; |
693 | |
694 | /* |
695 | * we deal with the discriminator; it's an enum |
696 | */ |
697 | if (!xdr_enum (xdrs, dscmp)) |
698 | { |
699 | return FALSE; |
700 | } |
701 | dscm = *dscmp; |
702 | |
703 | /* |
704 | * search choices for a value that matches the discriminator. |
705 | * if we find one, execute the xdr routine for that value. |
706 | */ |
707 | for (; choices->proc != NULL_xdrproc_t; choices++) |
708 | { |
709 | if (choices->value == dscm) |
710 | return (*(choices->proc)) (xdrs, unp, LASTUNSIGNED); |
711 | } |
712 | |
713 | /* |
714 | * no match - execute the default xdr routine if there is one |
715 | */ |
716 | return ((dfault == NULL_xdrproc_t) ? FALSE : |
717 | (*dfault) (xdrs, unp, LASTUNSIGNED)); |
718 | } |
719 | libc_hidden_nolink_sunrpc (xdr_union, GLIBC_2_0) |
720 | |
721 | |
722 | /* |
723 | * Non-portable xdr primitives. |
724 | * Care should be taken when moving these routines to new architectures. |
725 | */ |
726 | |
727 | |
728 | /* |
729 | * XDR null terminated ASCII strings |
730 | * xdr_string deals with "C strings" - arrays of bytes that are |
731 | * terminated by a NUL character. The parameter cpp references a |
732 | * pointer to storage; If the pointer is null, then the necessary |
733 | * storage is allocated. The last parameter is the max allowed length |
734 | * of the string as specified by a protocol. |
735 | */ |
736 | bool_t |
737 | xdr_string (XDR *xdrs, char **cpp, u_int maxsize) |
738 | { |
739 | char *sp = *cpp; /* sp is the actual string pointer */ |
740 | /* Initialize to silence the compiler. It is not really needed because SIZE |
741 | never actually gets used without being initialized. */ |
742 | u_int size = 0; |
743 | u_int nodesize; |
744 | |
745 | /* |
746 | * first deal with the length since xdr strings are counted-strings |
747 | */ |
748 | switch (xdrs->x_op) |
749 | { |
750 | case XDR_FREE: |
751 | if (sp == NULL) |
752 | { |
753 | return TRUE; /* already free */ |
754 | } |
755 | /* fall through... */ |
756 | case XDR_ENCODE: |
757 | if (sp == NULL) |
758 | return FALSE; |
759 | size = strlen (sp); |
760 | break; |
761 | case XDR_DECODE: |
762 | break; |
763 | } |
764 | if (!xdr_u_int (xdrs, &size)) |
765 | { |
766 | return FALSE; |
767 | } |
768 | if (size > maxsize) |
769 | { |
770 | return FALSE; |
771 | } |
772 | nodesize = size + 1; |
773 | if (nodesize == 0) |
774 | { |
775 | /* This means an overflow. It a bug in the caller which |
776 | provided a too large maxsize but nevertheless catch it |
777 | here. */ |
778 | return FALSE; |
779 | } |
780 | |
781 | /* |
782 | * now deal with the actual bytes |
783 | */ |
784 | switch (xdrs->x_op) |
785 | { |
786 | case XDR_DECODE: |
787 | if (sp == NULL) |
788 | *cpp = sp = (char *) mem_alloc (nodesize); |
789 | if (sp == NULL) |
790 | { |
791 | (void) __fxprintf (NULL, "%s: %s" , __func__, _("out of memory\n" )); |
792 | return FALSE; |
793 | } |
794 | sp[size] = 0; |
795 | /* Fall through. */ |
796 | |
797 | case XDR_ENCODE: |
798 | return xdr_opaque (xdrs, sp, size); |
799 | |
800 | case XDR_FREE: |
801 | mem_free (sp, nodesize); |
802 | *cpp = NULL; |
803 | return TRUE; |
804 | } |
805 | return FALSE; |
806 | } |
807 | #ifdef EXPORT_RPC_SYMBOLS |
808 | libc_hidden_def (xdr_string) |
809 | #else |
810 | libc_hidden_nolink_sunrpc (xdr_string, GLIBC_2_0) |
811 | #endif |
812 | |
813 | /* |
814 | * Wrapper for xdr_string that can be called directly from |
815 | * routines like clnt_call |
816 | */ |
817 | bool_t |
818 | xdr_wrapstring (XDR *xdrs, char **cpp) |
819 | { |
820 | if (xdr_string (xdrs, cpp, LASTUNSIGNED)) |
821 | { |
822 | return TRUE; |
823 | } |
824 | return FALSE; |
825 | } |
826 | #ifdef EXPORT_RPC_SYMBOLS |
827 | libc_hidden_def (xdr_wrapstring) |
828 | #else |
829 | libc_hidden_nolink_sunrpc (xdr_wrapstring, GLIBC_2_0) |
830 | #endif |
831 | |