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