1 /* $OpenBSD: xdr.c,v 1.9 2005/08/08 08:05:35 espie 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
xdr_free(xdrproc_t proc,char * objp)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
xdr_void(void)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
xdr_int(XDR * xdrs,int * ip)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
xdr_u_int(XDR * xdrs,u_int * up)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
xdr_long(XDR * xdrs,long int * lp)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
xdr_u_long(XDR * xdrs,u_long * ulp)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
xdr_int32_t(XDR * xdrs,int32_t * int32_p)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
xdr_u_int32_t(XDR * xdrs,u_int32_t * u_int32_p)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
xdr_short(XDR * xdrs,short int * sp)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
xdr_u_short(XDR * xdrs,u_short * usp)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
xdr_int16_t(XDR * xdrs,int16_t * int16_p)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
xdr_u_int16_t(XDR * xdrs,u_int16_t * u_int16_p)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
xdr_char(XDR * xdrs,char * cp)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
xdr_u_char(XDR * xdrs,u_char * cp)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
xdr_bool(XDR * xdrs,int32_t * bp)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
xdr_enum(XDR * xdrs,int32_t * ep)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
xdr_opaque(XDR * xdrs,caddr_t cp,u_int cnt)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
xdr_bytes(XDR * xdrs,char ** cpp,u_int * sizep,u_int maxsize)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
xdr_netobj(XDR * xdrs,struct netobj * np)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
xdr_union(XDR * xdrs,int32_t * dscmp,char * unp,struct xdr_discrim * choices,xdrproc_t dfault)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
xdr_string(XDR * xdrs,char ** cpp,u_int maxsize)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
xdr_wrapstring(XDR * xdrs,char ** cpp)666 xdr_wrapstring(XDR *xdrs, char **cpp)
667 {
668 return xdr_string(xdrs, cpp, LASTUNSIGNED);
669 }
670