xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr.c (revision 22cc5755)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30 /*
31  * Portions of this source code were derived from Berkeley
32  * 4.3 BSD under license from the Regents of the University of
33  * California.
34  */
35 
36 /*
37  * Generic XDR routines implementation.
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 #include "mt.h"
44 #include <stdlib.h>
45 #include <sys/types.h>
46 #include <sys/isa_defs.h>
47 #include <syslog.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <limits.h>
52 #include <rpc/types.h>
53 #include <rpc/xdr.h>
54 #include <inttypes.h>
55 #include <sys/sysmacros.h>
56 #include <assert.h>
57 
58 #pragma weak xdr_int64_t = xdr_hyper
59 #pragma weak xdr_uint64_t = xdr_u_hyper
60 #pragma weak xdr_int32_t = xdr_int
61 #pragma weak xdr_uint32_t = xdr_u_int
62 #pragma weak xdr_int16_t = xdr_short
63 #pragma weak xdr_uint16_t = xdr_u_short
64 #pragma weak xdr_int8_t = xdr_char
65 #pragma weak xdr_uint8_t = xdr_u_char
66 
67 /*
68  * The following routine was part of a workaround for an rpcgen
69  * that was fixed, this routine should be removed sometime.
70  */
71 #pragma weak xdr_ulonglong_t = xdr_u_longlong_t
72 
73 /*
74  * constants specific to the xdr "protocol"
75  */
76 #define	XDR_FALSE	((uint_t)0)
77 #define	XDR_TRUE	((uint_t)1)
78 #define	LASTUNSIGNED	((uint_t)0-1)
79 
80 /* fragment size to use when doing an xdr_string() */
81 #define	FRAGMENT	65536
82 
83 /*
84  * for unit alignment
85  */
86 static const char xdr_zero[BYTES_PER_XDR_UNIT]	= { 0 };
87 
88 /*
89  * Free a data structure using XDR
90  * Not a filter, but a convenient utility nonetheless
91  */
92 void
xdr_free(xdrproc_t proc,char * objp)93 xdr_free(xdrproc_t proc, char *objp)
94 {
95 	XDR x;
96 
97 	x.x_op = XDR_FREE;
98 	(*proc)(&x, objp);
99 }
100 
101 /*
102  * XDR nothing
103  */
104 bool_t
xdr_void(void)105 xdr_void(void)
106 {
107 	return (TRUE);
108 }
109 
110 /*
111  * xdr_time_t  sends time_t value over the wire.
112  * Due to RPC Protocol limitation, it can only send
113  * up to 32-bit integer quantity over the wire.
114  *
115  */
116 bool_t
xdr_time_t(XDR * xdrs,time_t * tp)117 xdr_time_t(XDR *xdrs, time_t *tp)
118 {
119 	int32_t i;
120 
121 	switch (xdrs->x_op) {
122 	case XDR_ENCODE:
123 	/*
124 	 * Check for the time overflow, when encoding it.
125 	 * Don't want to send OTW the time value too large to
126 	 * handle by the protocol.
127 	 */
128 #if defined(_LP64)
129 	if (*tp > INT32_MAX)
130 		*tp = INT32_MAX;
131 	else if (*tp < INT32_MIN)
132 		*tp = INT32_MIN;
133 #endif
134 		i =  (int32_t)*tp;
135 		return (XDR_PUTINT32(xdrs, &i));
136 
137 	case XDR_DECODE:
138 		if (!XDR_GETINT32(xdrs, &i))
139 			return (FALSE);
140 		*tp = (time_t)i;
141 		return (TRUE);
142 
143 	case XDR_FREE:
144 		return (TRUE);
145 	}
146 	return (FALSE);
147 }
148 
149 /*
150  * XDR integers
151  */
152 bool_t
xdr_int(XDR * xdrs,int * ip)153 xdr_int(XDR *xdrs, int *ip)
154 {
155 	switch (xdrs->x_op) {
156 	case XDR_ENCODE:
157 		return (XDR_PUTINT32(xdrs, ip));
158 	case XDR_DECODE:
159 		return (XDR_GETINT32(xdrs, ip));
160 	case XDR_FREE:
161 		return (TRUE);
162 	}
163 	return (FALSE);
164 }
165 
166 /*
167  * XDR unsigned integers
168  */
169 bool_t
xdr_u_int(XDR * xdrs,uint_t * up)170 xdr_u_int(XDR *xdrs, uint_t *up)
171 {
172 	switch (xdrs->x_op) {
173 	case XDR_ENCODE:
174 		return (XDR_PUTINT32(xdrs, (int *)up));
175 	case XDR_DECODE:
176 		return (XDR_GETINT32(xdrs, (int *)up));
177 	case XDR_FREE:
178 		return (TRUE);
179 	}
180 	return (FALSE);
181 }
182 
183 /*
184  * The definition of xdr_long()/xdr_u_long() is kept for backward
185  * compatibitlity.
186  * XDR long integers, same as xdr_u_long
187  */
188 bool_t
xdr_long(XDR * xdrs,long * lp)189 xdr_long(XDR *xdrs, long *lp)
190 {
191 	int32_t i;
192 
193 	switch (xdrs->x_op) {
194 	case XDR_ENCODE:
195 #if defined(_LP64)
196 		if ((*lp > INT32_MAX) || (*lp < INT32_MIN))
197 			return (FALSE);
198 #endif
199 		i = (int32_t)*lp;
200 		return (XDR_PUTINT32(xdrs, &i));
201 	case XDR_DECODE:
202 		if (!XDR_GETINT32(xdrs, &i))
203 			return (FALSE);
204 		*lp = (long)i;
205 		return (TRUE);
206 	case XDR_FREE:
207 		return (TRUE);
208 	}
209 	return (FALSE);
210 }
211 
212 /*
213  * XDR unsigned long integers
214  * same as xdr_long
215  */
216 bool_t
xdr_u_long(XDR * xdrs,ulong_t * ulp)217 xdr_u_long(XDR *xdrs, ulong_t *ulp)
218 {
219 	uint32_t ui;
220 
221 	switch (xdrs->x_op) {
222 	case XDR_ENCODE:
223 #if defined(_LP64)
224 		if (*ulp > UINT32_MAX)
225 			return (FALSE);
226 #endif
227 		ui = (uint32_t)*ulp;
228 		return (XDR_PUTINT32(xdrs, (int32_t *)&ui));
229 	case XDR_DECODE:
230 		if (!XDR_GETINT32(xdrs, (int32_t *)&ui))
231 			return (FALSE);
232 		*ulp = (ulong_t)ui;
233 		return (TRUE);
234 	case XDR_FREE:
235 		return (TRUE);
236 	}
237 	return (FALSE);
238 }
239 
240 /*
241  * XDR short integers
242  */
243 bool_t
xdr_short(XDR * xdrs,short * sp)244 xdr_short(XDR *xdrs, short *sp)
245 {
246 	int32_t l;
247 
248 	switch (xdrs->x_op) {
249 	case XDR_ENCODE:
250 		l = (int32_t)*sp;
251 		return (XDR_PUTINT32(xdrs, &l));
252 	case XDR_DECODE:
253 		if (!XDR_GETINT32(xdrs, &l))
254 			return (FALSE);
255 		*sp = (short)l;
256 		return (TRUE);
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,ushort_t * usp)267 xdr_u_short(XDR *xdrs, ushort_t *usp)
268 {
269 	uint_t i;
270 
271 	switch (xdrs->x_op) {
272 	case XDR_ENCODE:
273 		i = (uint_t)*usp;
274 		return (XDR_PUTINT32(xdrs, (int *)&i));
275 	case XDR_DECODE:
276 		if (!XDR_GETINT32(xdrs, (int *)&i))
277 			return (FALSE);
278 		*usp = (ushort_t)i;
279 		return (TRUE);
280 	case XDR_FREE:
281 		return (TRUE);
282 	}
283 	return (FALSE);
284 }
285 
286 
287 /*
288  * XDR a char
289  */
290 bool_t
xdr_char(XDR * xdrs,char * cp)291 xdr_char(XDR *xdrs, char *cp)
292 {
293 	int i;
294 
295 	switch (xdrs->x_op) {
296 	case XDR_ENCODE:
297 		i = (*cp);
298 		return (XDR_PUTINT32(xdrs, &i));
299 	case XDR_DECODE:
300 		if (!XDR_GETINT32(xdrs, &i))
301 			return (FALSE);
302 		*cp = (char)i;
303 		return (TRUE);
304 	case XDR_FREE:
305 		return (TRUE);
306 	}
307 	return (FALSE);
308 }
309 
310 /*
311  * XDR an unsigned char
312  */
313 bool_t
xdr_u_char(XDR * xdrs,uchar_t * cp)314 xdr_u_char(XDR *xdrs, uchar_t *cp)
315 {
316 	int i;
317 
318 	switch (xdrs->x_op) {
319 	case XDR_ENCODE:
320 		i = (*cp);
321 		return (XDR_PUTINT32(xdrs, &i));
322 	case XDR_DECODE:
323 		if (!XDR_GETINT32(xdrs, &i))
324 			return (FALSE);
325 		*cp = (uchar_t)i;
326 		return (TRUE);
327 	case XDR_FREE:
328 		return (TRUE);
329 	}
330 	return (FALSE);
331 }
332 
333 /*
334  * XDR booleans
335  */
336 bool_t
xdr_bool(XDR * xdrs,bool_t * bp)337 xdr_bool(XDR *xdrs, bool_t *bp)
338 {
339 	int i;
340 
341 	switch (xdrs->x_op) {
342 	case XDR_ENCODE:
343 		i = *bp ? XDR_TRUE : XDR_FALSE;
344 		return (XDR_PUTINT32(xdrs, &i));
345 	case XDR_DECODE:
346 		if (!XDR_GETINT32(xdrs, &i))
347 			return (FALSE);
348 		*bp = (i == XDR_FALSE) ? FALSE : TRUE;
349 		return (TRUE);
350 	case XDR_FREE:
351 		return (TRUE);
352 	}
353 	return (FALSE);
354 }
355 
356 /*
357  * XDR enumerations
358  */
359 bool_t
xdr_enum(XDR * xdrs,enum_t * ep)360 xdr_enum(XDR *xdrs, enum_t *ep)
361 {
362 	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
363 
364 	/*
365 	 * enums are treated as ints
366 	 */
367 	/* CONSTCOND */
368 	assert(sizeof (enum sizecheck) == sizeof (int32_t));
369 	return (xdr_int(xdrs, (int *)ep));
370 }
371 
372 /*
373  * XDR opaque data
374  * Allows the specification of a fixed size sequence of opaque bytes.
375  * cp points to the opaque object and cnt gives the byte length.
376  */
377 bool_t
xdr_opaque(XDR * xdrs,caddr_t cp,const uint_t cnt)378 xdr_opaque(XDR *xdrs, caddr_t cp, const uint_t cnt)
379 {
380 	uint_t rndup;
381 	char crud[BYTES_PER_XDR_UNIT];
382 
383 	/*
384 	 * round byte count to full xdr units
385 	 */
386 	rndup = cnt % BYTES_PER_XDR_UNIT;
387 	if ((int)rndup > 0)
388 		rndup = BYTES_PER_XDR_UNIT - rndup;
389 
390 	switch (xdrs->x_op) {
391 	case XDR_DECODE:
392 		if (!XDR_GETBYTES(xdrs, cp, cnt))
393 			return (FALSE);
394 		if (rndup == 0)
395 			return (TRUE);
396 		return (XDR_GETBYTES(xdrs, crud, rndup));
397 	case XDR_ENCODE:
398 		if (!XDR_PUTBYTES(xdrs, cp, cnt))
399 			return (FALSE);
400 		if (rndup == 0)
401 			return (TRUE);
402 		return (XDR_PUTBYTES(xdrs, (caddr_t)&xdr_zero[0], rndup));
403 	case XDR_FREE:
404 		return (TRUE);
405 	}
406 	return (FALSE);
407 }
408 
409 /*
410  * XDR counted bytes
411  * *cpp is a pointer to the bytes, *sizep is the count.
412  * If *cpp is NULL maxsize bytes are allocated
413  */
414 
415 static const char xdr_err[] = "xdr_%s: out of memory";
416 
417 bool_t
xdr_bytes(XDR * xdrs,char ** cpp,uint_t * sizep,const uint_t maxsize)418 xdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, const uint_t maxsize)
419 {
420 	char *sp = *cpp;  /* sp is the actual string pointer */
421 	uint_t nodesize;
422 
423 	/*
424 	 * first deal with the length since xdr bytes are counted
425 	 * We decided not to use MACRO XDR_U_INT here, because the
426 	 * advantages here will be miniscule compared to xdr_bytes.
427 	 * This saved us 100 bytes in the library size.
428 	 */
429 	if (!xdr_u_int(xdrs, sizep))
430 		return (FALSE);
431 	nodesize = *sizep;
432 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE))
433 		return (FALSE);
434 
435 	/*
436 	 * now deal with the actual bytes
437 	 */
438 	switch (xdrs->x_op) {
439 	case XDR_DECODE:
440 		if (nodesize == 0)
441 			return (TRUE);
442 		if (sp == NULL)
443 			*cpp = sp = malloc(nodesize);
444 		if (sp == NULL) {
445 			(void) syslog(LOG_ERR, xdr_err, (const char *)"bytes");
446 			return (FALSE);
447 		}
448 		/*FALLTHROUGH*/
449 	case XDR_ENCODE:
450 		return (xdr_opaque(xdrs, sp, nodesize));
451 	case XDR_FREE:
452 		if (sp != NULL) {
453 			free(sp);
454 			*cpp = NULL;
455 		}
456 		return (TRUE);
457 	}
458 	return (FALSE);
459 }
460 
461 /*
462  * Implemented here due to commonality of the object.
463  */
464 bool_t
xdr_netobj(XDR * xdrs,struct netobj * np)465 xdr_netobj(XDR *xdrs, struct netobj *np)
466 {
467 	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
468 }
469 
470 /*
471  * XDR a descriminated union
472  * Support routine for discriminated unions.
473  * You create an array of xdrdiscrim structures, terminated with
474  * an entry with a null procedure pointer.  The routine gets
475  * the discriminant value and then searches the array of xdrdiscrims
476  * looking for that value.  It calls the procedure given in the xdrdiscrim
477  * to handle the discriminant.  If there is no specific routine a default
478  * routine may be called.
479  * If there is no specific or default routine an error is returned.
480  */
481 bool_t
xdr_union(XDR * xdrs,enum_t * dscmp,char * unp,const struct xdr_discrim * choices,const xdrproc_t dfault)482 xdr_union(XDR *xdrs, enum_t *dscmp, char *unp,
483     const struct xdr_discrim *choices, const xdrproc_t dfault)
484 {
485 	enum_t dscm;
486 
487 	/*
488 	 * we deal with the discriminator;  it's an enum
489 	 */
490 	if (!xdr_enum(xdrs, dscmp))
491 		return (FALSE);
492 	dscm = *dscmp;
493 
494 	/*
495 	 * search choices for a value that matches the discriminator.
496 	 * if we find one, execute the xdr routine for that value.
497 	 */
498 	for (; choices->proc != NULL_xdrproc_t; choices++) {
499 		if (choices->value == dscm)
500 			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
501 	}
502 
503 	/*
504 	 * no match - execute the default xdr routine if there is one
505 	 */
506 	return ((dfault == NULL_xdrproc_t) ? FALSE :
507 	    (*dfault)(xdrs, unp, LASTUNSIGNED));
508 }
509 
510 
511 /*
512  * Non-portable xdr primitives.
513  * Care should be taken when moving these routines to new architectures.
514  */
515 
516 
517 /*
518  * XDR null terminated ASCII strings
519  * xdr_string deals with "C strings" - arrays of bytes that are
520  * terminated by a NULL character.  The parameter cpp references a
521  * pointer to storage; If the pointer is null, then the necessary
522  * storage is allocated.  The last parameter is the max allowed length
523  * of the string as specified by a protocol.
524  */
525 bool_t
xdr_string(XDR * xdrs,char ** cpp,const uint_t maxsize)526 xdr_string(XDR *xdrs, char **cpp, const uint_t maxsize)
527 {
528 	char *newsp, *sp = *cpp;  /* sp is the actual string pointer */
529 	uint_t size, block;
530 	uint64_t bytesread;
531 
532 	/*
533 	 * first deal with the length since xdr strings are counted-strings
534 	 */
535 	switch (xdrs->x_op) {
536 	case XDR_FREE:
537 		if (sp == NULL)
538 			return (TRUE);	/* already free */
539 		/*FALLTHROUGH*/
540 	case XDR_ENCODE:
541 		size = (sp != NULL) ? (uint_t)strlen(sp) : 0;
542 		break;
543 	}
544 	/*
545 	 * We decided not to use MACRO XDR_U_INT here, because the
546 	 * advantages here will be miniscule compared to xdr_string.
547 	 * This saved us 100 bytes in the library size.
548 	 */
549 	if (!xdr_u_int(xdrs, &size))
550 		return (FALSE);
551 	if (size > maxsize)
552 		return (FALSE);
553 
554 	/*
555 	 * now deal with the actual bytes
556 	 */
557 	switch (xdrs->x_op) {
558 	case XDR_DECODE:
559 		/* if buffer is already given, call xdr_opaque() directly */
560 		if (sp != NULL) {
561 			if (!xdr_opaque(xdrs, sp, size))
562 				return (FALSE);
563 			sp[size] = 0;
564 			return (TRUE);
565 		}
566 
567 		/*
568 		 * We have to allocate a buffer of size 'size'. To avoid
569 		 * malloc()ing one huge chunk, we'll read the bytes in max
570 		 * FRAGMENT size blocks and keep realloc()ing. 'block' is
571 		 * the number of bytes to read in each xdr_opaque() and
572 		 * 'bytesread' is what we have already read. sp is NULL
573 		 * when we are in the loop for the first time.
574 		 */
575 		bytesread = 0;
576 		do {
577 			block = MIN(size - bytesread, FRAGMENT);
578 			/*
579 			 * allocate enough for 'bytesread + block' bytes and
580 			 * one extra for the terminating NULL.
581 			 */
582 			newsp = realloc(sp, bytesread + block + 1);
583 			if (newsp == NULL) {
584 				if (sp != NULL)
585 					free(sp);
586 				return (FALSE);
587 			}
588 			sp = newsp;
589 			if (!xdr_opaque(xdrs, &sp[bytesread], block)) {
590 				free(sp);
591 				return (FALSE);
592 			}
593 			bytesread += block;
594 		} while (bytesread < size);
595 
596 		sp[bytesread] = 0; /* terminate the string with a NULL */
597 		*cpp = sp;
598 		return (TRUE);
599 	case XDR_ENCODE:
600 		return (xdr_opaque(xdrs, sp, size));
601 	case XDR_FREE:
602 		free(sp);
603 		*cpp = NULL;
604 		return (TRUE);
605 	}
606 	return (FALSE);
607 }
608 
609 bool_t
xdr_hyper(XDR * xdrs,longlong_t * hp)610 xdr_hyper(XDR *xdrs, longlong_t *hp)
611 {
612 	switch (xdrs->x_op) {
613 	case XDR_ENCODE:
614 #if defined(_LONG_LONG_HTOL)
615 		if (XDR_PUTINT32(xdrs, (int *)hp) == TRUE)
616 			/* LINTED pointer cast */
617 			return (XDR_PUTINT32(xdrs, (int *)((char *)hp +
618 			    BYTES_PER_XDR_UNIT)));
619 #else
620 		/* LINTED pointer cast */
621 		if (XDR_PUTINT32(xdrs, (int *)((char *)hp +
622 		    BYTES_PER_XDR_UNIT)) == TRUE)
623 			return (XDR_PUTINT32(xdrs, (int32_t *)hp));
624 #endif
625 		return (FALSE);
626 	case XDR_DECODE:
627 #if defined(_LONG_LONG_HTOL)
628 		if (XDR_GETINT32(xdrs, (int *)hp) == FALSE ||
629 		    /* LINTED pointer cast */
630 		    (XDR_GETINT32(xdrs, (int *)((char *)hp +
631 		    BYTES_PER_XDR_UNIT)) == FALSE))
632 			return (FALSE);
633 #else
634 		/* LINTED pointer cast */
635 		if ((XDR_GETINT32(xdrs, (int *)((char *)hp +
636 		    BYTES_PER_XDR_UNIT)) == FALSE) ||
637 		    (XDR_GETINT32(xdrs, (int *)hp) == FALSE))
638 			return (FALSE);
639 #endif
640 		return (TRUE);
641 	case XDR_FREE:
642 		return (TRUE);
643 	}
644 	return (FALSE);
645 }
646 
647 bool_t
xdr_u_hyper(XDR * xdrs,u_longlong_t * hp)648 xdr_u_hyper(XDR *xdrs, u_longlong_t *hp)
649 {
650 	return (xdr_hyper(xdrs, (longlong_t *)hp));
651 }
652 
653 bool_t
xdr_longlong_t(XDR * xdrs,longlong_t * hp)654 xdr_longlong_t(XDR *xdrs, longlong_t *hp)
655 {
656 	return (xdr_hyper(xdrs, hp));
657 }
658 
659 bool_t
xdr_u_longlong_t(XDR * xdrs,u_longlong_t * hp)660 xdr_u_longlong_t(XDR *xdrs, u_longlong_t *hp)
661 {
662 	return (xdr_hyper(xdrs, (longlong_t *)hp));
663 }
664 
665 /*
666  * Wrapper for xdr_string that can be called directly from
667  * routines like clnt_call
668  */
669 bool_t
xdr_wrapstring(XDR * xdrs,char ** cpp)670 xdr_wrapstring(XDR *xdrs, char **cpp)
671 {
672 	return (xdr_string(xdrs, cpp, LASTUNSIGNED));
673 }
674