xdr.c revision e8031f0a8ed0e45c6d8847c5e09424e66fd34a4b
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A/*
2N/A * Portions of this source code were derived from Berkeley
2N/A * 4.3 BSD under license from the Regents of the University of
2N/A * California.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * Generic XDR routines implementation.
2N/A *
2N/A * These are the "generic" xdr routines used to serialize and de-serialize
2N/A * most common data items. See xdr.h for more info on the interface to
2N/A * xdr.
2N/A */
2N/A#include "mt.h"
2N/A#include <stdlib.h>
2N/A#include <sys/types.h>
2N/A#include <sys/isa_defs.h>
2N/A#include <syslog.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <limits.h>
2N/A#include <rpc/types.h>
2N/A#include <rpc/xdr.h>
2N/A#include <inttypes.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <assert.h>
2N/A
2N/A#pragma weak xdr_int64_t = xdr_hyper
2N/A#pragma weak xdr_uint64_t = xdr_u_hyper
2N/A#pragma weak xdr_int32_t = xdr_int
2N/A#pragma weak xdr_uint32_t = xdr_u_int
2N/A#pragma weak xdr_int16_t = xdr_short
2N/A#pragma weak xdr_uint16_t = xdr_u_short
2N/A#pragma weak xdr_int8_t = xdr_char
2N/A#pragma weak xdr_uint8_t = xdr_u_char
2N/A
2N/A/*
2N/A * The following routine was part of a workaround for an rpcgen
2N/A * that was fixed, this routine should be removed sometime.
2N/A */
2N/A#pragma weak xdr_ulonglong_t = xdr_u_longlong_t
2N/A
2N/A/*
2N/A * constants specific to the xdr "protocol"
2N/A */
2N/A#define XDR_FALSE ((uint_t)0)
2N/A#define XDR_TRUE ((uint_t)1)
2N/A#define LASTUNSIGNED ((uint_t)0-1)
2N/A
2N/A/* fragment size to use when doing an xdr_string() */
2N/A#define FRAGMENT 65536
2N/A
2N/A/*
2N/A * for unit alignment
2N/A */
2N/Astatic const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0 };
2N/A
2N/A/*
2N/A * Free a data structure using XDR
2N/A * Not a filter, but a convenient utility nonetheless
2N/A */
2N/Avoid
2N/Axdr_free(xdrproc_t proc, char *objp)
2N/A{
2N/A XDR x;
2N/A
2N/A x.x_op = XDR_FREE;
2N/A (*proc)(&x, objp);
2N/A}
2N/A
2N/A/*
2N/A * XDR nothing
2N/A */
2N/Abool_t
2N/Axdr_void(void)
2N/A{
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * xdr_time_t sends time_t value over the wire.
2N/A * Due to RPC Protocol limitation, it can only send
2N/A * up to 32-bit integer quantity over the wire.
2N/A *
2N/A */
2N/Abool_t
2N/Axdr_time_t(XDR *xdrs, time_t *tp)
2N/A{
2N/A int32_t i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A /*
2N/A * Check for the time overflow, when encoding it.
2N/A * Don't want to send OTW the time value too large to
2N/A * handle by the protocol.
2N/A */
2N/A#if defined(_LP64)
2N/A if (*tp > INT32_MAX)
2N/A *tp = INT32_MAX;
2N/A else if (*tp < INT32_MIN)
2N/A *tp = INT32_MIN;
2N/A#endif
2N/A i = (int32_t)*tp;
2N/A return (XDR_PUTINT32(xdrs, &i));
2N/A
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &i))
2N/A return (FALSE);
2N/A *tp = (time_t)i;
2N/A return (TRUE);
2N/A
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR integers
2N/A */
2N/Abool_t
2N/Axdr_int(XDR *xdrs, int *ip)
2N/A{
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A return (XDR_PUTINT32(xdrs, ip));
2N/A case XDR_DECODE:
2N/A return (XDR_GETINT32(xdrs, ip));
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR unsigned integers
2N/A */
2N/Abool_t
2N/Axdr_u_int(XDR *xdrs, uint_t *up)
2N/A{
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A return (XDR_PUTINT32(xdrs, (int *)up));
2N/A case XDR_DECODE:
2N/A return (XDR_GETINT32(xdrs, (int *)up));
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * The definition of xdr_long()/xdr_u_long() is kept for backward
2N/A * compatibitlity.
2N/A * XDR long integers, same as xdr_u_long
2N/A */
2N/Abool_t
2N/Axdr_long(XDR *xdrs, long *lp)
2N/A{
2N/A int32_t i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A#if defined(_LP64)
2N/A if ((*lp > INT32_MAX) || (*lp < INT32_MIN))
2N/A return (FALSE);
2N/A#endif
2N/A i = (int32_t)*lp;
2N/A return (XDR_PUTINT32(xdrs, &i));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &i))
2N/A return (FALSE);
2N/A *lp = (long)i;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR unsigned long integers
2N/A * same as xdr_long
2N/A */
2N/Abool_t
2N/Axdr_u_long(XDR *xdrs, ulong_t *ulp)
2N/A{
2N/A uint32_t ui;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A#if defined(_LP64)
2N/A if (*ulp > UINT32_MAX)
2N/A return (FALSE);
2N/A#endif
2N/A ui = (uint32_t)*ulp;
2N/A return (XDR_PUTINT32(xdrs, (int32_t *)&ui));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, (int32_t *)&ui))
2N/A return (FALSE);
2N/A *ulp = (ulong_t)ui;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR short integers
2N/A */
2N/Abool_t
2N/Axdr_short(XDR *xdrs, short *sp)
2N/A{
2N/A int32_t l;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A l = (int32_t)*sp;
2N/A return (XDR_PUTINT32(xdrs, &l));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &l))
2N/A return (FALSE);
2N/A *sp = (short)l;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR unsigned short integers
2N/A */
2N/Abool_t
2N/Axdr_u_short(XDR *xdrs, ushort_t *usp)
2N/A{
2N/A uint_t i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A i = (uint_t)*usp;
2N/A return (XDR_PUTINT32(xdrs, (int *)&i));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, (int *)&i))
2N/A return (FALSE);
2N/A *usp = (ushort_t)i;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * XDR a char
2N/A */
2N/Abool_t
2N/Axdr_char(XDR *xdrs, char *cp)
2N/A{
2N/A int i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A i = (*cp);
2N/A return (XDR_PUTINT32(xdrs, &i));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &i))
2N/A return (FALSE);
2N/A *cp = (char)i;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR an unsigned char
2N/A */
2N/Abool_t
2N/Axdr_u_char(XDR *xdrs, uchar_t *cp)
2N/A{
2N/A int i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A i = (*cp);
2N/A return (XDR_PUTINT32(xdrs, &i));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &i))
2N/A return (FALSE);
2N/A *cp = (uchar_t)i;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR booleans
2N/A */
2N/Abool_t
2N/Axdr_bool(XDR *xdrs, bool_t *bp)
2N/A{
2N/A int i;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_ENCODE:
2N/A i = *bp ? XDR_TRUE : XDR_FALSE;
2N/A return (XDR_PUTINT32(xdrs, &i));
2N/A case XDR_DECODE:
2N/A if (!XDR_GETINT32(xdrs, &i))
2N/A return (FALSE);
2N/A *bp = (i == XDR_FALSE) ? FALSE : TRUE;
2N/A return (TRUE);
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR enumerations
2N/A */
2N/Abool_t
2N/Axdr_enum(XDR *xdrs, enum_t *ep)
2N/A{
2N/A enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
2N/A
2N/A /*
2N/A * enums are treated as ints
2N/A */
2N/A /* CONSTCOND */
2N/A assert(sizeof (enum sizecheck) == sizeof (int32_t));
2N/A return (xdr_int(xdrs, (int *)ep));
2N/A}
2N/A
2N/A/*
2N/A * XDR opaque data
2N/A * Allows the specification of a fixed size sequence of opaque bytes.
2N/A * cp points to the opaque object and cnt gives the byte length.
2N/A */
2N/Abool_t
2N/Axdr_opaque(XDR *xdrs, caddr_t cp, const uint_t cnt)
2N/A{
2N/A uint_t rndup;
2N/A char crud[BYTES_PER_XDR_UNIT];
2N/A
2N/A /*
2N/A * if no data we are done
2N/A */
2N/A if (cnt == 0)
2N/A return (TRUE);
2N/A
2N/A /*
2N/A * round byte count to full xdr units
2N/A */
2N/A rndup = cnt % BYTES_PER_XDR_UNIT;
2N/A if ((int)rndup > 0)
2N/A rndup = BYTES_PER_XDR_UNIT - rndup;
2N/A
2N/A switch (xdrs->x_op) {
2N/A case XDR_DECODE:
2N/A if (!XDR_GETBYTES(xdrs, cp, cnt))
2N/A return (FALSE);
2N/A if (rndup == 0)
2N/A return (TRUE);
2N/A return (XDR_GETBYTES(xdrs, crud, rndup));
2N/A case XDR_ENCODE:
2N/A if (!XDR_PUTBYTES(xdrs, cp, cnt))
2N/A return (FALSE);
2N/A if (rndup == 0)
2N/A return (TRUE);
2N/A return (XDR_PUTBYTES(xdrs, (caddr_t)&xdr_zero[0], rndup));
2N/A case XDR_FREE:
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * XDR counted bytes
2N/A * *cpp is a pointer to the bytes, *sizep is the count.
2N/A * If *cpp is NULL maxsize bytes are allocated
2N/A */
2N/A
2N/Astatic const char xdr_err[] = "xdr_%s: out of memory";
2N/A
2N/Abool_t
2N/Axdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, const uint_t maxsize)
2N/A{
2N/A char *sp = *cpp; /* sp is the actual string pointer */
2N/A uint_t nodesize;
2N/A
2N/A /*
2N/A * first deal with the length since xdr bytes are counted
2N/A * We decided not to use MACRO XDR_U_INT here, because the
2N/A * advantages here will be miniscule compared to xdr_bytes.
2N/A * This saved us 100 bytes in the library size.
2N/A */
2N/A if (!xdr_u_int(xdrs, sizep))
2N/A return (FALSE);
2N/A nodesize = *sizep;
2N/A if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE))
2N/A return (FALSE);
2N/A
2N/A /*
2N/A * now deal with the actual bytes
2N/A */
2N/A switch (xdrs->x_op) {
2N/A case XDR_DECODE:
2N/A if (nodesize == 0)
2N/A return (TRUE);
2N/A if (sp == NULL)
2N/A *cpp = sp = malloc(nodesize);
2N/A if (sp == NULL) {
2N/A (void) syslog(LOG_ERR, xdr_err, (const char *)"bytes");
2N/A return (FALSE);
2N/A }
2N/A /*FALLTHROUGH*/
2N/A case XDR_ENCODE:
2N/A return (xdr_opaque(xdrs, sp, nodesize));
2N/A case XDR_FREE:
2N/A if (sp != NULL) {
2N/A free(sp);
2N/A *cpp = NULL;
2N/A }
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * Implemented here due to commonality of the object.
2N/A */
2N/Abool_t
2N/Axdr_netobj(XDR *xdrs, struct netobj *np)
2N/A{
2N/A return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
2N/A}
2N/A
2N/A/*
2N/A * XDR a descriminated union
2N/A * Support routine for discriminated unions.
2N/A * You create an array of xdrdiscrim structures, terminated with
2N/A * an entry with a null procedure pointer. The routine gets
2N/A * the discriminant value and then searches the array of xdrdiscrims
2N/A * looking for that value. It calls the procedure given in the xdrdiscrim
2N/A * to handle the discriminant. If there is no specific routine a default
2N/A * routine may be called.
2N/A * If there is no specific or default routine an error is returned.
2N/A */
2N/Abool_t
2N/Axdr_union(XDR *xdrs, enum_t *dscmp, char *unp,
2N/A const struct xdr_discrim *choices, const xdrproc_t dfault)
2N/A{
2N/A enum_t dscm;
2N/A
2N/A /*
2N/A * we deal with the discriminator; it's an enum
2N/A */
2N/A if (!xdr_enum(xdrs, dscmp))
2N/A return (FALSE);
2N/A dscm = *dscmp;
2N/A
2N/A /*
2N/A * search choices for a value that matches the discriminator.
2N/A * if we find one, execute the xdr routine for that value.
2N/A */
2N/A for (; choices->proc != NULL_xdrproc_t; choices++) {
2N/A if (choices->value == dscm)
2N/A return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
2N/A }
2N/A
2N/A /*
2N/A * no match - execute the default xdr routine if there is one
2N/A */
2N/A return ((dfault == NULL_xdrproc_t) ? FALSE :
2N/A (*dfault)(xdrs, unp, LASTUNSIGNED));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Non-portable xdr primitives.
2N/A * Care should be taken when moving these routines to new architectures.
2N/A */
2N/A
2N/A
2N/A/*
2N/A * XDR null terminated ASCII strings
2N/A * xdr_string deals with "C strings" - arrays of bytes that are
2N/A * terminated by a NULL character. The parameter cpp references a
2N/A * pointer to storage; If the pointer is null, then the necessary
2N/A * storage is allocated. The last parameter is the max allowed length
2N/A * of the string as specified by a protocol.
2N/A */
2N/Abool_t
2N/Axdr_string(XDR *xdrs, char **cpp, const uint_t maxsize)
2N/A{
2N/A char *newsp, *sp = *cpp; /* sp is the actual string pointer */
2N/A uint_t size, block;
2N/A uint64_t bytesread;
2N/A
2N/A /*
2N/A * first deal with the length since xdr strings are counted-strings
2N/A */
2N/A switch (xdrs->x_op) {
2N/A case XDR_FREE:
2N/A if (sp == NULL)
2N/A return (TRUE); /* already free */
2N/A /*FALLTHROUGH*/
2N/A case XDR_ENCODE:
2N/A size = (sp != NULL) ? (uint_t)strlen(sp) : 0;
2N/A break;
2N/A }
2N/A /*
2N/A * We decided not to use MACRO XDR_U_INT here, because the
2N/A * advantages here will be miniscule compared to xdr_string.
2N/A * This saved us 100 bytes in the library size.
2N/A */
2N/A if (!xdr_u_int(xdrs, &size))
2N/A return (FALSE);
2N/A if (size > maxsize)
2N/A return (FALSE);
2N/A
2N/A /*
2N/A * now deal with the actual bytes
2N/A */
2N/A switch (xdrs->x_op) {
2N/A case XDR_DECODE:
2N/A /* if buffer is already given, call xdr_opaque() directly */
2N/A if (sp != NULL) {
2N/A if (!xdr_opaque(xdrs, sp, size))
2N/A return (FALSE);
2N/A sp[size] = 0;
2N/A return (TRUE);
2N/A }
2N/A
2N/A /*
2N/A * We have to allocate a buffer of size 'size'. To avoid
2N/A * malloc()ing one huge chunk, we'll read the bytes in max
2N/A * FRAGMENT size blocks and keep realloc()ing. 'block' is
2N/A * the number of bytes to read in each xdr_opaque() and
2N/A * 'bytesread' is what we have already read. sp is NULL
2N/A * when we are in the loop for the first time.
2N/A */
2N/A bytesread = 0;
2N/A do {
2N/A block = MIN(size - bytesread, FRAGMENT);
2N/A /*
2N/A * allocate enough for 'bytesread + block' bytes and
2N/A * one extra for the terminating NULL.
2N/A */
2N/A newsp = realloc(sp, bytesread + block + 1);
2N/A if (newsp == NULL) {
2N/A if (sp != NULL)
2N/A free(sp);
2N/A return (FALSE);
2N/A }
2N/A sp = newsp;
2N/A if (!xdr_opaque(xdrs, &sp[bytesread], block)) {
2N/A free(sp);
2N/A return (FALSE);
2N/A }
2N/A bytesread += block;
2N/A } while (bytesread < size);
2N/A
2N/A sp[bytesread] = 0; /* terminate the string with a NULL */
2N/A *cpp = sp;
2N/A return (TRUE);
2N/A case XDR_ENCODE:
2N/A return (xdr_opaque(xdrs, sp, size));
2N/A case XDR_FREE:
2N/A free(sp);
2N/A *cpp = NULL;
2N/A return (TRUE);
2N/A }
2N/A return (FALSE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_hyper(XDR *xdrs, longlong_t *hp)
2N/A{
2N/A if (xdrs->x_op == XDR_ENCODE) {
2N/A#if defined(_LONG_LONG_HTOL)
2N/A if (XDR_PUTINT32(xdrs, (int *)hp) == TRUE)
2N/A /* LINTED pointer cast */
2N/A return (XDR_PUTINT32(xdrs, (int *)((char *)hp +
2N/A BYTES_PER_XDR_UNIT)));
2N/A#else
2N/A /* LINTED pointer cast */
2N/A if (XDR_PUTINT32(xdrs, (int *)((char *)hp +
2N/A BYTES_PER_XDR_UNIT)) == TRUE)
2N/A return (XDR_PUTINT32(xdrs, (int32_t *)hp));
2N/A#endif
2N/A return (FALSE);
2N/A }
2N/A
2N/A if (xdrs->x_op == XDR_DECODE) {
2N/A#if defined(_LONG_LONG_HTOL)
2N/A if (XDR_GETINT32(xdrs, (int *)hp) == FALSE ||
2N/A /* LINTED pointer cast */
2N/A (XDR_GETINT32(xdrs, (int *)((char *)hp +
2N/A BYTES_PER_XDR_UNIT)) == FALSE))
2N/A return (FALSE);
2N/A#else
2N/A /* LINTED pointer cast */
2N/A if ((XDR_GETINT32(xdrs, (int *)((char *)hp +
2N/A BYTES_PER_XDR_UNIT)) == FALSE) ||
2N/A (XDR_GETINT32(xdrs, (int *)hp) == FALSE))
2N/A return (FALSE);
2N/A#endif
2N/A return (TRUE);
2N/A }
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_u_hyper(XDR *xdrs, u_longlong_t *hp)
2N/A{
2N/A return (xdr_hyper(xdrs, (longlong_t *)hp));
2N/A}
2N/A
2N/Abool_t
2N/Axdr_longlong_t(XDR *xdrs, longlong_t *hp)
2N/A{
2N/A return (xdr_hyper(xdrs, hp));
2N/A}
2N/A
2N/Abool_t
2N/Axdr_u_longlong_t(XDR *xdrs, u_longlong_t *hp)
2N/A{
2N/A return (xdr_hyper(xdrs, (longlong_t *)hp));
2N/A}
2N/A
2N/A/*
2N/A * Wrapper for xdr_string that can be called directly from
2N/A * routines like clnt_call
2N/A */
2N/Abool_t
2N/Axdr_wrapstring(XDR *xdrs, char **cpp)
2N/A{
2N/A return (xdr_string(xdrs, cpp, LASTUNSIGNED));
2N/A}
2N/A