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