1 /* $OpenBSD: xdr.c,v 1.17 2022/12/27 17:10:06 jmc Exp $ */
2
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
34 /*
35 * xdr.c, Generic XDR routines implementation.
36 *
37 * These are the "generic" xdr routines used to serialize and de-serialize
38 * most common data items. See xdr.h for more info on the interface to
39 * xdr.
40 */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <rpc/types.h>
47 #include <rpc/xdr.h>
48
49 /*
50 * constants specific to the xdr "protocol"
51 */
52 #define XDR_FALSE ((long) 0)
53 #define XDR_TRUE ((long) 1)
54 #define LASTUNSIGNED ((u_int) 0-1)
55
56 /*
57 * for unit alignment
58 */
59 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
60
61 /*
62 * Free a data structure using XDR
63 * Not a filter, but a convenient utility nonetheless
64 */
65 void
xdr_free(xdrproc_t proc,char * objp)66 xdr_free(xdrproc_t proc, char *objp)
67 {
68 XDR x;
69
70 x.x_op = XDR_FREE;
71 (*proc)(&x, objp);
72 }
73 DEF_WEAK(xdr_free);
74
75 /*
76 * XDR nothing
77 */
78 bool_t
xdr_void(void)79 xdr_void(void)
80 /* XDR *xdrs; */
81 /* caddr_t addr; */
82 {
83
84 return (TRUE);
85 }
86 DEF_WEAK(xdr_void);
87
88
89 /*
90 * XDR integers
91 */
92 bool_t
xdr_int(XDR * xdrs,int * ip)93 xdr_int(XDR *xdrs, int *ip)
94 {
95 long l;
96
97 switch (xdrs->x_op) {
98
99 case XDR_ENCODE:
100 l = (long) *ip;
101 return (XDR_PUTLONG(xdrs, &l));
102
103 case XDR_DECODE:
104 if (!XDR_GETLONG(xdrs, &l)) {
105 return (FALSE);
106 }
107 *ip = (int) l;
108 return (TRUE);
109
110 case XDR_FREE:
111 return (TRUE);
112 }
113 return (FALSE);
114 }
115 DEF_WEAK(xdr_int);
116
117 /*
118 * XDR unsigned integers
119 */
120 bool_t
xdr_u_int(XDR * xdrs,u_int * up)121 xdr_u_int(XDR *xdrs, u_int *up)
122 {
123 u_long l;
124
125 switch (xdrs->x_op) {
126
127 case XDR_ENCODE:
128 l = (u_long) *up;
129 return (XDR_PUTLONG(xdrs, (long *)&l));
130
131 case XDR_DECODE:
132 if (!XDR_GETLONG(xdrs, (long *)&l)) {
133 return (FALSE);
134 }
135 *up = (u_int) l;
136 return (TRUE);
137
138 case XDR_FREE:
139 return (TRUE);
140 }
141 return (FALSE);
142 }
143 DEF_WEAK(xdr_u_int);
144
145
146 /*
147 * XDR long integers
148 * same as xdr_u_long - open coded to save a proc call!
149 */
150 bool_t
xdr_long(XDR * xdrs,long int * lp)151 xdr_long(XDR *xdrs, long int *lp)
152 {
153 switch (xdrs->x_op) {
154 case XDR_ENCODE:
155 return (XDR_PUTLONG(xdrs, lp));
156 case XDR_DECODE:
157 return (XDR_GETLONG(xdrs, lp));
158 case XDR_FREE:
159 return (TRUE);
160 }
161
162 return (FALSE);
163 }
164 DEF_WEAK(xdr_long);
165
166 /*
167 * XDR unsigned long integers
168 * same as xdr_long - open coded to save a proc call!
169 */
170 bool_t
xdr_u_long(XDR * xdrs,u_long * ulp)171 xdr_u_long(XDR *xdrs, u_long *ulp)
172 {
173 switch (xdrs->x_op) {
174 case XDR_ENCODE:
175 return (XDR_PUTLONG(xdrs, (long *)ulp));
176 case XDR_DECODE:
177 return (XDR_GETLONG(xdrs, (long *)ulp));
178 case XDR_FREE:
179 return (TRUE);
180 }
181 return (FALSE);
182 }
183 DEF_WEAK(xdr_u_long);
184
185
186 /*
187 * XDR 32-bit integers
188 * same as xdr_u_int32_t - open coded to save a proc call!
189 */
190 bool_t
xdr_int32_t(XDR * xdrs,int32_t * int32_p)191 xdr_int32_t(XDR *xdrs, int32_t *int32_p)
192 {
193 long l;
194
195 switch (xdrs->x_op) {
196
197 case XDR_ENCODE:
198 l = (long) *int32_p;
199 return (XDR_PUTLONG(xdrs, &l));
200
201 case XDR_DECODE:
202 if (!XDR_GETLONG(xdrs, &l)) {
203 return (FALSE);
204 }
205 *int32_p = (int32_t) l;
206 return (TRUE);
207
208 case XDR_FREE:
209 return (TRUE);
210 }
211 return (FALSE);
212 }
213
214 /*
215 * XDR unsigned 32-bit integers
216 * same as xdr_int32_t - open coded to save a proc call!
217 */
218 bool_t
xdr_u_int32_t(XDR * xdrs,u_int32_t * u_int32_p)219 xdr_u_int32_t(XDR *xdrs, u_int32_t *u_int32_p)
220 {
221 u_long l;
222
223 switch (xdrs->x_op) {
224
225 case XDR_ENCODE:
226 l = (u_long) *u_int32_p;
227 return (XDR_PUTLONG(xdrs, (long *)&l));
228
229 case XDR_DECODE:
230 if (!XDR_GETLONG(xdrs, (long *)&l)) {
231 return (FALSE);
232 }
233 *u_int32_p = (u_int32_t) l;
234 return (TRUE);
235
236 case XDR_FREE:
237 return (TRUE);
238 }
239 return (FALSE);
240 }
241 DEF_WEAK(xdr_u_int32_t);
242
243
244 /*
245 * XDR short integers
246 */
247 bool_t
xdr_short(XDR * xdrs,short int * sp)248 xdr_short(XDR *xdrs, short int *sp)
249 {
250 long l;
251
252 switch (xdrs->x_op) {
253
254 case XDR_ENCODE:
255 l = (long) *sp;
256 return (XDR_PUTLONG(xdrs, &l));
257
258 case XDR_DECODE:
259 if (!XDR_GETLONG(xdrs, &l)) {
260 return (FALSE);
261 }
262 *sp = (short) l;
263 return (TRUE);
264
265 case XDR_FREE:
266 return (TRUE);
267 }
268 return (FALSE);
269 }
270 DEF_WEAK(xdr_short);
271
272 /*
273 * XDR unsigned short integers
274 */
275 bool_t
xdr_u_short(XDR * xdrs,u_short * usp)276 xdr_u_short(XDR *xdrs, u_short *usp)
277 {
278 u_long l;
279
280 switch (xdrs->x_op) {
281
282 case XDR_ENCODE:
283 l = (u_long) *usp;
284 return (XDR_PUTLONG(xdrs, (long *)&l));
285
286 case XDR_DECODE:
287 if (!XDR_GETLONG(xdrs, (long *)&l)) {
288 return (FALSE);
289 }
290 *usp = (u_short) l;
291 return (TRUE);
292
293 case XDR_FREE:
294 return (TRUE);
295 }
296 return (FALSE);
297 }
298 DEF_WEAK(xdr_u_short);
299
300
301 /*
302 * XDR 16-bit integers
303 */
304 bool_t
xdr_int16_t(XDR * xdrs,int16_t * int16_p)305 xdr_int16_t(XDR *xdrs, int16_t *int16_p)
306 {
307 long l;
308
309 switch (xdrs->x_op) {
310
311 case XDR_ENCODE:
312 l = (long) *int16_p;
313 return (XDR_PUTLONG(xdrs, &l));
314
315 case XDR_DECODE:
316 if (!XDR_GETLONG(xdrs, &l)) {
317 return (FALSE);
318 }
319 *int16_p = (int16_t) l;
320 return (TRUE);
321
322 case XDR_FREE:
323 return (TRUE);
324 }
325 return (FALSE);
326 }
327
328 /*
329 * XDR unsigned 16-bit integers
330 */
331 bool_t
xdr_u_int16_t(XDR * xdrs,u_int16_t * u_int16_p)332 xdr_u_int16_t(XDR *xdrs, u_int16_t *u_int16_p)
333 {
334 u_long l;
335
336 switch (xdrs->x_op) {
337
338 case XDR_ENCODE:
339 l = (u_long) *u_int16_p;
340 return (XDR_PUTLONG(xdrs, (long *)&l));
341
342 case XDR_DECODE:
343 if (!XDR_GETLONG(xdrs, (long *)&l)) {
344 return (FALSE);
345 }
346 *u_int16_p = (u_int16_t) l;
347 return (TRUE);
348
349 case XDR_FREE:
350 return (TRUE);
351 }
352 return (FALSE);
353 }
354
355
356 /*
357 * XDR a char
358 */
359 bool_t
xdr_char(XDR * xdrs,char * cp)360 xdr_char(XDR *xdrs, char *cp)
361 {
362 int i;
363
364 i = (*cp);
365 if (!xdr_int(xdrs, &i)) {
366 return (FALSE);
367 }
368 *cp = i;
369 return (TRUE);
370 }
371
372 /*
373 * XDR an unsigned char
374 */
375 bool_t
xdr_u_char(XDR * xdrs,u_char * cp)376 xdr_u_char(XDR *xdrs, u_char *cp)
377 {
378 u_int u;
379
380 u = (*cp);
381 if (!xdr_u_int(xdrs, &u)) {
382 return (FALSE);
383 }
384 *cp = u;
385 return (TRUE);
386 }
387
388 /*
389 * XDR booleans
390 */
391 bool_t
xdr_bool(XDR * xdrs,int32_t * bp)392 xdr_bool(XDR *xdrs, int32_t *bp)
393 {
394 long lb;
395
396 switch (xdrs->x_op) {
397
398 case XDR_ENCODE:
399 lb = *bp ? XDR_TRUE : XDR_FALSE;
400 return (XDR_PUTLONG(xdrs, &lb));
401
402 case XDR_DECODE:
403 if (!XDR_GETLONG(xdrs, &lb)) {
404 return (FALSE);
405 }
406 *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
407 return (TRUE);
408
409 case XDR_FREE:
410 return (TRUE);
411 }
412 return (FALSE);
413 }
414 DEF_WEAK(xdr_bool);
415
416 /*
417 * XDR enumerations
418 */
419 bool_t
xdr_enum(XDR * xdrs,int32_t * ep)420 xdr_enum(XDR *xdrs, int32_t *ep)
421 {
422 enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
423
424 /*
425 * enums are treated as ints
426 */
427 if (sizeof (enum sizecheck) == sizeof (long)) {
428 return (xdr_long(xdrs, (long *)ep));
429 } else if (sizeof (enum sizecheck) == sizeof (int)) {
430 return (xdr_int(xdrs, (int *)ep));
431 } else if (sizeof (enum sizecheck) == sizeof (short)) {
432 return (xdr_short(xdrs, (short *)ep));
433 } else {
434 return (FALSE);
435 }
436 }
437 DEF_WEAK(xdr_enum);
438
439 /*
440 * XDR opaque data
441 * Allows the specification of a fixed size sequence of opaque bytes.
442 * cp points to the opaque object and cnt gives the byte length.
443 */
444 bool_t
xdr_opaque(XDR * xdrs,caddr_t cp,u_int cnt)445 xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
446 {
447 u_int rndup;
448 static int crud[BYTES_PER_XDR_UNIT];
449
450 /*
451 * if no data we are done
452 */
453 if (cnt == 0)
454 return (TRUE);
455
456 /*
457 * round byte count to full xdr units
458 */
459 rndup = cnt % BYTES_PER_XDR_UNIT;
460 if (rndup > 0)
461 rndup = BYTES_PER_XDR_UNIT - rndup;
462
463 if (xdrs->x_op == XDR_DECODE) {
464 if (!XDR_GETBYTES(xdrs, cp, cnt)) {
465 return (FALSE);
466 }
467 if (rndup == 0)
468 return (TRUE);
469 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup));
470 }
471
472 if (xdrs->x_op == XDR_ENCODE) {
473 if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
474 return (FALSE);
475 }
476 if (rndup == 0)
477 return (TRUE);
478 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
479 }
480
481 if (xdrs->x_op == XDR_FREE) {
482 return (TRUE);
483 }
484
485 return (FALSE);
486 }
487 DEF_WEAK(xdr_opaque);
488
489 /*
490 * XDR counted bytes
491 * *cpp is a pointer to the bytes, *sizep is the count.
492 * If *cpp is NULL maxsize bytes are allocated
493 */
494 bool_t
xdr_bytes(XDR * xdrs,char ** cpp,u_int * sizep,u_int maxsize)495 xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
496 {
497 char *sp = *cpp; /* sp is the actual string pointer */
498 u_int nodesize;
499
500 /*
501 * first deal with the length since xdr bytes are counted
502 */
503 if (! xdr_u_int(xdrs, sizep)) {
504 return (FALSE);
505 }
506 nodesize = *sizep;
507 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
508 return (FALSE);
509 }
510
511 /*
512 * now deal with the actual bytes
513 */
514 switch (xdrs->x_op) {
515
516 case XDR_DECODE:
517 if (nodesize == 0) {
518 return (TRUE);
519 }
520 if (sp == NULL) {
521 *cpp = sp = (char *)mem_alloc(nodesize);
522 }
523 if (sp == NULL)
524 return (FALSE);
525 /* fall into ... */
526
527 case XDR_ENCODE:
528 return (xdr_opaque(xdrs, sp, nodesize));
529
530 case XDR_FREE:
531 if (sp != NULL) {
532 mem_free(sp, nodesize);
533 *cpp = NULL;
534 }
535 return (TRUE);
536 }
537 return (FALSE);
538 }
539 DEF_WEAK(xdr_bytes);
540
541 /*
542 * Implemented here due to commonality of the object.
543 */
544 bool_t
xdr_netobj(XDR * xdrs,struct netobj * np)545 xdr_netobj(XDR *xdrs, struct netobj *np)
546 {
547
548 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
549 }
550
551 /*
552 * XDR a discriminated union
553 * Support routine for discriminated unions.
554 * You create an array of xdrdiscrim structures, terminated with
555 * an entry with a null procedure pointer. The routine gets
556 * the discriminant value and then searches the array of xdrdiscrims
557 * looking for that value. It calls the procedure given in the xdrdiscrim
558 * to handle the discriminant. If there is no specific routine a default
559 * routine may be called.
560 * If there is no specific or default routine an error is returned.
561 */
562 bool_t
xdr_union(XDR * xdrs,int32_t * dscmp,char * unp,struct xdr_discrim * choices,xdrproc_t dfault)563 xdr_union(XDR *xdrs,
564 int32_t *dscmp, /* enum to decide which arm to work on */
565 char *unp, /* the union itself */
566 struct xdr_discrim *choices, /* [value, xdr proc] for each arm */
567 xdrproc_t dfault) /* default xdr routine */
568 {
569 enum_t dscm;
570
571 /*
572 * we deal with the discriminator; it's an enum
573 */
574 if (! xdr_enum(xdrs, dscmp)) {
575 return (FALSE);
576 }
577 dscm = *dscmp;
578
579 /*
580 * search choices for a value that matches the discriminator.
581 * if we find one, execute the xdr routine for that value.
582 */
583 for (; choices->proc != NULL; choices++) {
584 if (choices->value == dscm)
585 return ((*(choices->proc))(xdrs, unp));
586 }
587
588 /*
589 * no match - execute the default xdr routine if there is one
590 */
591 return ((dfault == NULL) ? FALSE :
592 (*dfault)(xdrs, unp));
593 }
594 DEF_WEAK(xdr_union);
595
596
597 /*
598 * Non-portable xdr primitives.
599 * Care should be taken when moving these routines to new architectures.
600 */
601
602
603 /*
604 * XDR null terminated ASCII strings
605 * xdr_string deals with "C strings" - arrays of bytes that are
606 * terminated by a NULL character. The parameter cpp references a
607 * pointer to storage; If the pointer is null, then the necessary
608 * storage is allocated. The last parameter is the max allowed length
609 * of the string as specified by a protocol.
610 */
611 bool_t
xdr_string(XDR * xdrs,char ** cpp,u_int maxsize)612 xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
613 {
614 char *sp = *cpp; /* sp is the actual string pointer */
615 u_int size;
616 u_int nodesize;
617
618 /*
619 * first deal with the length since xdr strings are counted-strings
620 */
621 switch (xdrs->x_op) {
622 case XDR_FREE:
623 if (sp == NULL) {
624 return(TRUE); /* already free */
625 }
626 /* fall through... */
627 case XDR_ENCODE:
628 size = strlen(sp);
629 break;
630 default:
631 break;
632 }
633 if (! xdr_u_int(xdrs, &size)) {
634 return (FALSE);
635 }
636 if (size > maxsize) {
637 return (FALSE);
638 }
639 nodesize = size + 1;
640
641 /*
642 * now deal with the actual bytes
643 */
644 switch (xdrs->x_op) {
645
646 case XDR_DECODE:
647 if (nodesize == 0) {
648 return (TRUE);
649 }
650 if (sp == NULL)
651 *cpp = sp = (char *)mem_alloc(nodesize);
652 if (sp == NULL)
653 return (FALSE);
654 sp[size] = 0;
655 /* fall into ... */
656
657 case XDR_ENCODE:
658 return (xdr_opaque(xdrs, sp, size));
659
660 case XDR_FREE:
661 mem_free(sp, nodesize);
662 *cpp = NULL;
663 return (TRUE);
664 }
665 return (FALSE);
666 }
667 DEF_WEAK(xdr_string);
668
669 /*
670 * Wrapper for xdr_string that can be called directly from
671 * routines like clnt_call
672 */
673 bool_t
xdr_wrapstring(XDR * xdrs,char ** cpp)674 xdr_wrapstring(XDR *xdrs, char **cpp)
675 {
676 return xdr_string(xdrs, cpp, LASTUNSIGNED);
677 }
678
679 bool_t
xdr_int64_t(XDR * xdrs,int64_t * llp)680 xdr_int64_t(XDR *xdrs, int64_t *llp)
681 {
682 u_long ul[2];
683
684 switch (xdrs->x_op) {
685 case XDR_ENCODE:
686 ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff;
687 ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff;
688 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
689 return (FALSE);
690 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
691 case XDR_DECODE:
692 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
693 return (FALSE);
694 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
695 return (FALSE);
696 *llp = (int64_t)
697 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
698 return (TRUE);
699 case XDR_FREE:
700 return (TRUE);
701 }
702 /* NOTREACHED */
703 return (FALSE);
704 }
705
706 bool_t
xdr_u_int64_t(XDR * xdrs,u_int64_t * ullp)707 xdr_u_int64_t(XDR *xdrs, u_int64_t *ullp)
708 {
709 u_long ul[2];
710
711 switch (xdrs->x_op) {
712 case XDR_ENCODE:
713 ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
714 ul[1] = (u_long)(*ullp) & 0xffffffff;
715 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
716 return (FALSE);
717 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
718 case XDR_DECODE:
719 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
720 return (FALSE);
721 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
722 return (FALSE);
723 *ullp = (u_int64_t)
724 (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
725 return (TRUE);
726 case XDR_FREE:
727 return (TRUE);
728 }
729 /* NOTREACHED */
730 return (FALSE);
731 }
732