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
xdr_free(xdrproc_t proc,char * objp)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
xdr_void(void)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
xdr_time_t(XDR * xdrs,time_t * tp)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
xdr_int(XDR * xdrs,int * ip)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
xdr_u_int(XDR * xdrs,uint_t * up)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
xdr_long(XDR * xdrs,long * lp)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
xdr_u_long(XDR * xdrs,ulong_t * ulp)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
xdr_short(XDR * xdrs,short * sp)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
xdr_u_short(XDR * xdrs,ushort_t * usp)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
xdr_char(XDR * xdrs,char * cp)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
xdr_u_char(XDR * xdrs,uchar_t * cp)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
xdr_bool(XDR * xdrs,bool_t * bp)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
xdr_enum(XDR * xdrs,enum_t * ep)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
xdr_opaque(XDR * xdrs,caddr_t cp,const uint_t cnt)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
xdr_bytes(XDR * xdrs,char ** cpp,uint_t * sizep,const uint_t maxsize)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
xdr_netobj(XDR * xdrs,struct netobj * np)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
xdr_union(XDR * xdrs,enum_t * dscmp,char * unp,const struct xdr_discrim * choices,const xdrproc_t dfault)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
xdr_string(XDR * xdrs,char ** cpp,const uint_t maxsize)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
xdr_hyper(XDR * xdrs,longlong_t * hp)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
xdr_u_hyper(XDR * xdrs,u_longlong_t * hp)655 xdr_u_hyper(XDR *xdrs, u_longlong_t *hp)
656 {
657 return (xdr_hyper(xdrs, (longlong_t *)hp));
658 }
659
660 bool_t
xdr_longlong_t(XDR * xdrs,longlong_t * hp)661 xdr_longlong_t(XDR *xdrs, longlong_t *hp)
662 {
663 return (xdr_hyper(xdrs, hp));
664 }
665
666 bool_t
xdr_u_longlong_t(XDR * xdrs,u_longlong_t * hp)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
xdr_wrapstring(XDR * xdrs,char ** cpp)677 xdr_wrapstring(XDR *xdrs, char **cpp)
678 {
679 return (xdr_string(xdrs, cpp, LASTUNSIGNED));
680 }
681