xref: /openbsd/lib/libc/rpc/xdr.c (revision 2c53affb)
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