xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr.c (revision 61961e0f)
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 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30  * Portions of this source code were derived from Berkeley
31  * 4.3 BSD under license from the Regents of the University of
32  * California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * xdr.c, Generic XDR routines implementation.
39  *
40  * These are the "generic" xdr routines used to serialize and de-serialize
41  * most common data items.  See xdr.h for more info on the interface to
42  * xdr.
43  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 	 * if no data we are done
385 	 */
386 	if (cnt == 0)
387 		return (TRUE);
388 
389 	/*
390 	 * round byte count to full xdr units
391 	 */
392 	rndup = cnt % BYTES_PER_XDR_UNIT;
393 	if ((int)rndup > 0)
394 		rndup = BYTES_PER_XDR_UNIT - rndup;
395 
396 	switch (xdrs->x_op) {
397 	case XDR_DECODE:
398 		if (!XDR_GETBYTES(xdrs, cp, cnt))
399 			return (FALSE);
400 		if (rndup == 0)
401 			return (TRUE);
402 		return (XDR_GETBYTES(xdrs, crud, rndup));
403 	case XDR_ENCODE:
404 		if (!XDR_PUTBYTES(xdrs, cp, cnt))
405 			return (FALSE);
406 		if (rndup == 0)
407 			return (TRUE);
408 		return (XDR_PUTBYTES(xdrs, (caddr_t)&xdr_zero[0], rndup));
409 	case XDR_FREE:
410 		return (TRUE);
411 	}
412 	return (FALSE);
413 }
414 
415 /*
416  * XDR counted bytes
417  * *cpp is a pointer to the bytes, *sizep is the count.
418  * If *cpp is NULL maxsize bytes are allocated
419  */
420 
421 static const char xdr_err[] = "xdr_%s: out of memory";
422 
423 bool_t
424 xdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, const uint_t maxsize)
425 {
426 	char *sp = *cpp;  /* sp is the actual string pointer */
427 	uint_t nodesize;
428 
429 	/*
430 	 * first deal with the length since xdr bytes are counted
431 	 * We decided not to use MACRO XDR_U_INT here, because the
432 	 * advantages here will be miniscule compared to xdr_bytes.
433 	 * This saved us 100 bytes in the library size.
434 	 */
435 	if (!xdr_u_int(xdrs, sizep))
436 		return (FALSE);
437 	nodesize = *sizep;
438 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE))
439 		return (FALSE);
440 
441 	/*
442 	 * now deal with the actual bytes
443 	 */
444 	switch (xdrs->x_op) {
445 	case XDR_DECODE:
446 		if (nodesize == 0)
447 			return (TRUE);
448 		if (sp == NULL)
449 			*cpp = sp = malloc(nodesize);
450 		if (sp == NULL) {
451 			(void) syslog(LOG_ERR, xdr_err, (const char *)"bytes");
452 			return (FALSE);
453 		}
454 		/*FALLTHROUGH*/
455 	case XDR_ENCODE:
456 		return (xdr_opaque(xdrs, sp, nodesize));
457 	case XDR_FREE:
458 		if (sp != NULL) {
459 			free(sp);
460 			*cpp = NULL;
461 		}
462 		return (TRUE);
463 	}
464 	return (FALSE);
465 }
466 
467 /*
468  * Implemented here due to commonality of the object.
469  */
470 bool_t
471 xdr_netobj(XDR *xdrs, struct netobj *np)
472 {
473 	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
474 }
475 
476 /*
477  * XDR a descriminated union
478  * Support routine for discriminated unions.
479  * You create an array of xdrdiscrim structures, terminated with
480  * an entry with a null procedure pointer.  The routine gets
481  * the discriminant value and then searches the array of xdrdiscrims
482  * looking for that value.  It calls the procedure given in the xdrdiscrim
483  * to handle the discriminant.  If there is no specific routine a default
484  * routine may be called.
485  * If there is no specific or default routine an error is returned.
486  */
487 bool_t
488 xdr_union(XDR *xdrs, enum_t *dscmp, char *unp,
489 		const struct xdr_discrim *choices, const xdrproc_t dfault)
490 {
491 	enum_t dscm;
492 
493 	/*
494 	 * we deal with the discriminator;  it's an enum
495 	 */
496 	if (!xdr_enum(xdrs, dscmp))
497 		return (FALSE);
498 	dscm = *dscmp;
499 
500 	/*
501 	 * search choices for a value that matches the discriminator.
502 	 * if we find one, execute the xdr routine for that value.
503 	 */
504 	for (; choices->proc != NULL_xdrproc_t; choices++) {
505 		if (choices->value == dscm)
506 			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
507 	}
508 
509 	/*
510 	 * no match - execute the default xdr routine if there is one
511 	 */
512 	return ((dfault == NULL_xdrproc_t) ? FALSE :
513 	    (*dfault)(xdrs, unp, LASTUNSIGNED));
514 }
515 
516 
517 /*
518  * Non-portable xdr primitives.
519  * Care should be taken when moving these routines to new architectures.
520  */
521 
522 
523 /*
524  * XDR null terminated ASCII strings
525  * xdr_string deals with "C strings" - arrays of bytes that are
526  * terminated by a NULL character.  The parameter cpp references a
527  * pointer to storage; If the pointer is null, then the necessary
528  * storage is allocated.  The last parameter is the max allowed length
529  * of the string as specified by a protocol.
530  */
531 bool_t
532 xdr_string(XDR *xdrs, char **cpp, const uint_t maxsize)
533 {
534 	char *newsp, *sp = *cpp;  /* sp is the actual string pointer */
535 	uint_t size, block;
536 	uint64_t bytesread;
537 
538 	/*
539 	 * first deal with the length since xdr strings are counted-strings
540 	 */
541 	switch (xdrs->x_op) {
542 	case XDR_FREE:
543 		if (sp == NULL)
544 			return (TRUE);	/* already free */
545 		/*FALLTHROUGH*/
546 	case XDR_ENCODE:
547 		size = (sp != NULL) ? (uint_t)strlen(sp) : 0;
548 		break;
549 	}
550 	/*
551 	 * We decided not to use MACRO XDR_U_INT here, because the
552 	 * advantages here will be miniscule compared to xdr_string.
553 	 * This saved us 100 bytes in the library size.
554 	 */
555 	if (!xdr_u_int(xdrs, &size))
556 		return (FALSE);
557 	if (size > maxsize)
558 		return (FALSE);
559 
560 	/*
561 	 * now deal with the actual bytes
562 	 */
563 	switch (xdrs->x_op) {
564 	case XDR_DECODE:
565 		/* if buffer is already given, call xdr_opaque() directly */
566 		if (sp != NULL) {
567 			if (!xdr_opaque(xdrs, sp, size))
568 				return (FALSE);
569 			sp[size] = 0;
570 			return (TRUE);
571 		}
572 
573 		/*
574 		 * We have to allocate a buffer of size 'size'. To avoid
575 		 * malloc()ing one huge chunk, we'll read the bytes in max
576 		 * FRAGMENT size blocks and keep realloc()ing. 'block' is
577 		 * the number of bytes to read in each xdr_opaque() and
578 		 * 'bytesread' is what we have already read. sp is NULL
579 		 * when we are in the loop for the first time.
580 		 */
581 		bytesread = 0;
582 		do {
583 			block = MIN(size - bytesread, FRAGMENT);
584 			/*
585 			 * allocate enough for 'bytesread + block' bytes and
586 			 * one extra for the terminating NULL.
587 			 */
588 			newsp = realloc(sp, bytesread + block + 1);
589 			if (newsp == NULL) {
590 				if (sp != NULL)
591 					free(sp);
592 				return (FALSE);
593 			}
594 			sp = newsp;
595 			if (!xdr_opaque(xdrs, &sp[bytesread], block)) {
596 				free(sp);
597 				return (FALSE);
598 			}
599 			bytesread += block;
600 		} while (bytesread < size);
601 
602 		sp[bytesread] = 0; /* terminate the string with a NULL */
603 		*cpp = sp;
604 		return (TRUE);
605 	case XDR_ENCODE:
606 		return (xdr_opaque(xdrs, sp, size));
607 	case XDR_FREE:
608 		free(sp);
609 		*cpp = NULL;
610 		return (TRUE);
611 	}
612 	return (FALSE);
613 }
614 
615 bool_t
616 xdr_hyper(XDR *xdrs, longlong_t *hp)
617 {
618 	if (xdrs->x_op == XDR_ENCODE) {
619 #if defined(_LONG_LONG_HTOL)
620 		if (XDR_PUTINT32(xdrs, (int *)hp) == TRUE)
621 			/* LINTED pointer cast */
622 			return (XDR_PUTINT32(xdrs, (int *)((char *)hp +
623 				BYTES_PER_XDR_UNIT)));
624 #else
625 		/* LINTED pointer cast */
626 		if (XDR_PUTINT32(xdrs, (int *)((char *)hp +
627 				BYTES_PER_XDR_UNIT)) == TRUE)
628 			return (XDR_PUTINT32(xdrs, (int32_t *)hp));
629 #endif
630 		return (FALSE);
631 	}
632 
633 	if (xdrs->x_op == XDR_DECODE) {
634 #if defined(_LONG_LONG_HTOL)
635 		if (XDR_GETINT32(xdrs, (int *)hp) == FALSE ||
636 		    /* LINTED pointer cast */
637 		    (XDR_GETINT32(xdrs, (int *)((char *)hp +
638 				BYTES_PER_XDR_UNIT)) == FALSE))
639 			return (FALSE);
640 #else
641 		/* LINTED pointer cast */
642 		if ((XDR_GETINT32(xdrs, (int *)((char *)hp +
643 				BYTES_PER_XDR_UNIT)) == FALSE) ||
644 				(XDR_GETINT32(xdrs, (int *)hp) == FALSE))
645 			return (FALSE);
646 #endif
647 		return (TRUE);
648 	}
649 	return (TRUE);
650 }
651 
652 bool_t
653 xdr_u_hyper(XDR *xdrs, u_longlong_t *hp)
654 {
655 	return (xdr_hyper(xdrs, (longlong_t *)hp));
656 }
657 
658 bool_t
659 xdr_longlong_t(XDR *xdrs, longlong_t *hp)
660 {
661 	return (xdr_hyper(xdrs, hp));
662 }
663 
664 bool_t
665 xdr_u_longlong_t(XDR *xdrs, u_longlong_t *hp)
666 {
667 	return (xdr_hyper(xdrs, (longlong_t *)hp));
668 }
669 
670 /*
671  * Wrapper for xdr_string that can be called directly from
672  * routines like clnt_call
673  */
674 bool_t
675 xdr_wrapstring(XDR *xdrs, char **cpp)
676 {
677 	return (xdr_string(xdrs, cpp, LASTUNSIGNED));
678 }
679