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