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