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