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