#include <sys/byteorder.h>
#include <strings.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libmlrpc.h>
#include <ndr_wchar.h>
#define NDR_IS_UNION(T) \
(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_UNION)
#define NDR_IS_STRING(T) \
(((T)->type_flags & NDR_F_TYPEOP_MASK) == NDR_F_STRING)
extern ndr_typeinfo_t ndt_s_wchar;
static ndr_ref_t *ndr_enter_outer_queue(ndr_ref_t *);
extern int ndr__ulong(ndr_ref_t *);
int
ndo_process(ndr_stream_t *nds, ndr_typeinfo_t *ti, char *datum)
{
ndr_ref_t myref;
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.datum = datum;
myref.name = "PROCESS";
myref.ti = ti;
return (ndr_topmost(&myref));
}
int
ndo_operation(ndr_stream_t *nds, ndr_typeinfo_t *ti, int opnum, char *datum)
{
ndr_ref_t myref;
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.datum = datum;
myref.name = "OPERATION";
myref.ti = ti;
myref.inner_flags = NDR_F_SWITCH_IS;
myref.switch_is = opnum;
if (ti->type_flags != NDR_F_INTERFACE) {
NDR_SET_ERROR(&myref, NDR_ERR_NOT_AN_INTERFACE);
return (0);
}
return ((*ti->ndr_func)(&myref));
}
int
ndr_params(ndr_ref_t *params_ref)
{
ndr_typeinfo_t *ti = params_ref->ti;
if (ti->type_flags == NDR_F_OPERATION)
return (*ti->ndr_func) (params_ref);
else
return (ndr_topmost(params_ref));
}
int
ndr_topmost(ndr_ref_t *top_ref)
{
ndr_stream_t *nds;
ndr_typeinfo_t *ti;
ndr_ref_t *outer_ref = 0;
int is_varlen;
int is_string;
int error;
int rc;
unsigned n_fixed;
int params;
assert(top_ref);
assert(top_ref->stream);
assert(top_ref->ti);
nds = top_ref->stream;
ti = top_ref->ti;
is_varlen = ti->pdu_size_variable_part;
is_string = NDR_IS_STRING(ti);
assert(nds->outer_queue_tailp && !*nds->outer_queue_tailp);
assert(!nds->outer_current);
params = top_ref->inner_flags & NDR_F_PARAMS_MASK;
switch (params) {
case NDR_F_NONE:
case NDR_F_SWITCH_IS:
if (is_string || is_varlen) {
error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
NDR_SET_ERROR(outer_ref, error);
return (0);
}
n_fixed = ti->pdu_size_fixed_part;
break;
case NDR_F_SIZE_IS:
error = NDR_ERR_TOPMOST_VARLEN_ILLEGAL;
NDR_SET_ERROR(outer_ref, error);
return (0);
case NDR_F_DIMENSION_IS:
if (is_varlen) {
error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
NDR_SET_ERROR(outer_ref, error);
return (0);
}
n_fixed = ti->pdu_size_fixed_part * top_ref->dimension_is;
break;
case NDR_F_IS_POINTER:
case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
n_fixed = 4;
break;
case NDR_F_IS_REFERENCE:
case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
n_fixed = 0;
break;
default:
error = NDR_ERR_OUTER_PARAMS_BAD;
NDR_SET_ERROR(outer_ref, error);
return (0);
}
outer_ref = ndr_enter_outer_queue(top_ref);
if (!outer_ref)
return (0);
outer_ref->inner_flags = top_ref->inner_flags;
outer_ref->outer_flags = 0;
outer_ref->datum = top_ref->datum;
if (!ndr_outer_align(outer_ref))
return (0);
outer_ref->pdu_offset = nds->pdu_scan_offset;
rc = ndr_outer_grow(outer_ref, n_fixed);
if (!rc)
return (0);
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
nds->outer_current = outer_ref;
nds->outer_queue_tailp = &nds->outer_current->next;
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
rc = ndr_inner(outer_ref);
if (!rc)
return (0);
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
nds->outer_current = nds->outer_current->next;
return (ndr_run_outer_queue(nds));
}
static ndr_ref_t *
ndr_enter_outer_queue(ndr_ref_t *arg_ref)
{
ndr_stream_t *nds = arg_ref->stream;
ndr_ref_t *outer_ref;
outer_ref = (ndr_ref_t *)NDS_MALLOC(nds, sizeof (*outer_ref), arg_ref);
if (!outer_ref) {
NDR_SET_ERROR(arg_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
*outer_ref = *arg_ref;
outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
outer_ref->inner_flags = 0;
outer_ref->enclosing = nds->outer_current;
outer_ref->backptr = 0;
outer_ref->datum = 0;
assert(nds->outer_queue_tailp);
outer_ref->next = *nds->outer_queue_tailp;
*nds->outer_queue_tailp = outer_ref;
nds->outer_queue_tailp = &outer_ref->next;
return (outer_ref);
}
int
ndr_run_outer_queue(ndr_stream_t *nds)
{
while (nds->outer_current) {
nds->outer_queue_tailp = &nds->outer_current->next;
if (!ndr_outer(nds->outer_current))
return (0);
nds->outer_current = nds->outer_current->next;
}
return (1);
}
int
ndr_outer(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
int error = NDR_ERR_OUTER_PARAMS_BAD;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
NDR_TATTLE(outer_ref, "--OUTER--");
if (!ndr_outer_align(outer_ref))
return (0);
outer_ref->pdu_offset = nds->pdu_scan_offset;
if (is_union) {
error = NDR_ERR_OUTER_UNION_ILLEGAL;
NDR_SET_ERROR(outer_ref, error);
return (0);
}
switch (params) {
case NDR_F_NONE:
if (is_string)
return (ndr_outer_string(outer_ref));
if (is_varlen)
return (ndr_outer_conformant_construct(outer_ref));
return (ndr_outer_fixed(outer_ref));
case NDR_F_SIZE_IS:
case NDR_F_DIMENSION_IS:
case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
if (is_varlen) {
error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
break;
}
if (params & NDR_F_SIZE_IS)
return (ndr_outer_conformant_array(outer_ref));
else
return (ndr_outer_fixed_array(outer_ref));
default:
error = NDR_ERR_OUTER_PARAMS_BAD;
break;
}
NDR_SET_ERROR(outer_ref, error);
return (0);
}
int
ndr_outer_fixed(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
ndr_ref_t myref;
char *valp = NULL;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
int rc;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_alloc;
unsigned n_pdu_total;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
assert(!is_varlen && !is_string && !is_union);
assert(params == NDR_F_NONE);
n_hdr = 0;
n_fixed = ti->pdu_size_fixed_part;
assert(n_fixed > 0);
n_variable = 0;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
return (0);
}
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
break;
case NDR_M_OP_UNMARSHALL:
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
if (outer_ref->backptr)
*outer_ref->backptr = valp;
outer_ref->datum = valp;
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.enclosing = outer_ref;
myref.ti = outer_ref->ti;
myref.datum = outer_ref->datum;
myref.name = "FIXED-VALUE";
myref.outer_flags = NDR_F_NONE;
myref.inner_flags = NDR_F_NONE;
myref.pdu_offset = outer_ref->pdu_offset;
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
rc = ndr_inner(&myref);
if (!rc)
return (rc);
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
ndr_outer_fixed_array(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
ndr_ref_t myref;
char *valp = NULL;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
int rc;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_alloc;
unsigned n_pdu_total;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
assert(!is_varlen && !is_string && !is_union);
assert(params == NDR_F_DIMENSION_IS);
n_hdr = 0;
n_fixed = ti->pdu_size_fixed_part * outer_ref->dimension_is;
assert(n_fixed > 0);
n_variable = 0;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
return (0);
}
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
break;
case NDR_M_OP_UNMARSHALL:
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
if (outer_ref->backptr)
*outer_ref->backptr = valp;
outer_ref->datum = valp;
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.enclosing = outer_ref;
myref.ti = outer_ref->ti;
myref.datum = outer_ref->datum;
myref.name = "FIXED-ARRAY";
myref.outer_flags = NDR_F_NONE;
myref.inner_flags = NDR_F_DIMENSION_IS;
myref.dimension_is = outer_ref->dimension_is;
myref.pdu_offset = outer_ref->pdu_offset;
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
rc = ndr_inner(&myref);
if (!rc)
return (rc);
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
ndr_outer_conformant_array(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
ndr_ref_t myref;
char *valp = NULL;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
unsigned long size_is;
int rc;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_alloc;
unsigned n_pdu_total;
unsigned n_ptr_offset;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
assert(!is_varlen && !is_string && !is_union);
assert(params & NDR_F_SIZE_IS);
n_hdr = 4;
n_fixed = 0;
n_variable = ti->pdu_size_fixed_part * outer_ref->size_is;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
size_is = outer_ref->size_is;
rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
valp = outer_ref->datum;
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
return (0);
}
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
n_ptr_offset = 4;
break;
case NDR_M_OP_UNMARSHALL:
if (params & NDR_F_IS_REFERENCE) {
size_is = outer_ref->size_is;
n_ptr_offset = 0;
} else {
rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
if (size_is != outer_ref->size_is) {
NDR_SET_ERROR(outer_ref,
NDR_ERR_SIZE_IS_MISMATCH_PDU);
return (0);
}
n_ptr_offset = 4;
}
if (size_is > 0) {
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
}
if (outer_ref->backptr)
*outer_ref->backptr = valp;
outer_ref->datum = valp;
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
outer_ref->type_flags = NDR_F_NONE;
outer_ref->inner_flags = NDR_F_NONE;
if (size_is > 0) {
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.enclosing = outer_ref;
myref.ti = outer_ref->ti;
myref.datum = outer_ref->datum;
myref.name = "CONFORMANT-ARRAY";
myref.outer_flags = NDR_F_NONE;
myref.inner_flags = NDR_F_SIZE_IS;
myref.size_is = outer_ref->size_is;
myref.inner_flags = NDR_F_DIMENSION_IS;
myref.dimension_is = outer_ref->size_is;
myref.pdu_offset = outer_ref->pdu_offset + n_ptr_offset;
rc = ndr_inner(&myref);
if (!rc)
return (rc);
}
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
ndr_outer_conformant_construct(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
ndr_ref_t myref;
char *valp = NULL;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
unsigned long size_is;
int rc;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_alloc;
unsigned n_pdu_total;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
assert(is_varlen && !is_string && !is_union);
assert(params == NDR_F_NONE);
n_hdr = 4;
n_fixed = ti->pdu_size_fixed_part;
n_variable = 0;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
size_is = 0;
rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
valp = outer_ref->datum;
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
return (0);
}
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
break;
case NDR_M_OP_UNMARSHALL:
rc = ndr_outer_peek_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
n_variable = size_is * ti->pdu_size_variable_part;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
outer_ref->size_is = size_is;
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
if (outer_ref->backptr)
*outer_ref->backptr = valp;
outer_ref->datum = valp;
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_pdu_total;
outer_ref->type_flags = NDR_F_SIZE_IS;
outer_ref->inner_flags = NDR_F_NONE;
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.enclosing = outer_ref;
myref.ti = outer_ref->ti;
myref.datum = outer_ref->datum;
myref.name = "CONFORMANT-CONSTRUCT";
myref.outer_flags = NDR_F_NONE;
myref.inner_flags = NDR_F_NONE;
myref.size_is = outer_ref->size_is;
myref.pdu_offset = outer_ref->pdu_offset + 4;
rc = ndr_inner(&myref);
if (!rc)
return (rc);
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
if (outer_ref->inner_flags != NDR_F_SIZE_IS) {
NDR_SET_ERROR(&myref, NDR_ERR_SIZE_IS_MISMATCH_AFTER);
return (0);
}
return (1);
}
int
ndr_size_is(ndr_ref_t *ref)
{
ndr_stream_t *nds = ref->stream;
ndr_ref_t *outer_ref = nds->outer_current;
ndr_typeinfo_t *ti = outer_ref->ti;
unsigned long size_is;
int rc;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_pdu_total;
assert(ref->inner_flags & NDR_F_SIZE_IS);
size_is = ref->size_is;
if (outer_ref->type_flags != NDR_F_SIZE_IS) {
NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_UNEXPECTED);
return (0);
}
if (outer_ref->inner_flags & NDR_F_SIZE_IS) {
NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_DUPLICATED);
return (0);
}
n_hdr = 4;
n_fixed = ti->pdu_size_fixed_part;
n_variable = size_is * ti->pdu_size_variable_part;
n_pdu_total = n_hdr + n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
rc = ndr_outer_poke_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
break;
case NDR_M_OP_UNMARSHALL:
if (size_is != outer_ref->size_is) {
NDR_SET_ERROR(ref, NDR_ERR_SIZE_IS_MISMATCH_PDU);
return (0);
}
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
outer_ref->inner_flags |= NDR_F_SIZE_IS;
outer_ref->size_is = ref->size_is;
return (1);
}
int
ndr_outer_string(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
ndr_typeinfo_t *ti = outer_ref->ti;
ndr_ref_t myref;
char *valp = NULL;
unsigned is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int is_string = NDR_IS_STRING(ti);
int rc;
unsigned n_zeroes;
unsigned ix;
unsigned long size_is;
unsigned long first_is;
unsigned long length_is;
unsigned n_hdr;
unsigned n_fixed;
unsigned n_variable;
unsigned n_alloc;
unsigned n_pdu_total;
int params;
params = outer_ref->outer_flags & NDR_F_PARAMS_MASK;
assert(is_varlen && is_string && !is_union);
assert(params == NDR_F_NONE);
n_hdr = 12;
n_fixed = 0;
if (!ndr_outer_grow(outer_ref, n_hdr))
return (0);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_OUTER_PARAMS_BAD);
return (0);
}
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
if (ti == &ndt_s_wchar) {
size_t wlen;
wlen = ndr__mbstowcs(NULL, valp, NDR_STRING_MAX);
if (wlen == (size_t)-1) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
if ((nds->flags & NDS_F_NONULL) == 0)
wlen++;
if (wlen > NDR_STRING_MAX) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
size_is = wlen;
} else {
valp = outer_ref->datum;
n_zeroes = 0;
for (ix = 0; ix < NDR_STRING_MAX; ix++) {
if (valp[ix] == 0) {
n_zeroes++;
if (n_zeroes >= is_varlen &&
ix % is_varlen == 0) {
break;
}
} else {
n_zeroes = 0;
}
}
if (ix >= NDR_STRING_MAX) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
size_is = ix+1;
}
first_is = 0;
if (nds->flags & NDS_F_NOTERM)
length_is = size_is - 1;
else
length_is = size_is;
if (!ndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
!ndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
!ndr_outer_poke_sizing(outer_ref, 8, &length_is))
return (0);
break;
case NDR_M_OP_UNMARSHALL:
if (!ndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
!ndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
!ndr_outer_peek_sizing(outer_ref, 8, &length_is))
return (0);
if (size_is > NDR_STRING_MAX) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
return (0);
}
if (first_is != 0) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
return (0);
}
if (length_is > size_is) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
if (ti == &ndt_s_wchar) {
n_alloc = (size_is + 1) * NDR_MB_CHAR_MAX;
} else {
n_alloc = (size_is + 1) * is_varlen;
}
valp = NDS_MALLOC(nds, n_alloc, outer_ref);
if (!valp) {
NDR_SET_ERROR(outer_ref, NDR_ERR_MALLOC_FAILED);
return (0);
}
bzero(valp, (size_is+1) * is_varlen);
if (outer_ref->backptr)
*outer_ref->backptr = valp;
outer_ref->datum = valp;
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
n_variable = length_is * is_varlen;
n_pdu_total = n_hdr + n_fixed + n_variable;
n_alloc = n_fixed + n_variable;
rc = ndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
if (length_is > 0) {
bzero(&myref, sizeof (myref));
myref.stream = nds;
myref.enclosing = outer_ref;
myref.ti = outer_ref->ti;
myref.datum = outer_ref->datum;
myref.name = "OUTER-STRING";
myref.outer_flags = NDR_F_IS_STRING;
myref.inner_flags = NDR_F_NONE;
myref.size_is = size_is;
myref.strlen_is = length_is;
}
myref.pdu_offset = outer_ref->pdu_offset + 12;
if ((size_is == 0) && (first_is == 0) && (length_is == 0)) {
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
if ((size_is != 0) && (length_is != 0)) {
rc = ndr_inner(&myref);
if (!rc)
return (rc);
}
nds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
ndr_outer_peek_sizing(ndr_ref_t *outer_ref, unsigned offset,
unsigned long *sizing_p)
{
ndr_stream_t *nds = outer_ref->stream;
unsigned long pdu_offset;
int rc;
pdu_offset = outer_ref->pdu_offset + offset;
if (pdu_offset < nds->outer_current->pdu_offset ||
pdu_offset > nds->outer_current->pdu_end_offset ||
pdu_offset+4 > nds->outer_current->pdu_end_offset) {
NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
return (0);
}
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
return (0);
case NDR_M_OP_UNMARSHALL:
rc = NDS_GET_PDU(nds, pdu_offset, 4, (char *)sizing_p,
nds->swap, outer_ref);
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
return (rc);
}
int
ndr_outer_poke_sizing(ndr_ref_t *outer_ref, unsigned offset,
unsigned long *sizing_p)
{
ndr_stream_t *nds = outer_ref->stream;
unsigned long pdu_offset;
int rc;
pdu_offset = outer_ref->pdu_offset + offset;
if (pdu_offset < nds->outer_current->pdu_offset ||
pdu_offset > nds->outer_current->pdu_end_offset ||
pdu_offset+4 > nds->outer_current->pdu_end_offset) {
NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
return (0);
}
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
rc = NDS_PUT_PDU(nds, pdu_offset, 4, (char *)sizing_p,
nds->swap, outer_ref);
break;
case NDR_M_OP_UNMARSHALL:
NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
return (0);
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
return (rc);
}
int
ndr_outer_align(ndr_ref_t *outer_ref)
{
ndr_stream_t *nds = outer_ref->stream;
int rc;
unsigned n_pad;
unsigned align;
if (outer_ref->packed_alignment && outer_ref->ti != &ndt_s_wchar) {
align = outer_ref->ti->alignment;
n_pad = ((align + 1) - nds->pdu_scan_offset) & align;
} else {
n_pad = NDR_ALIGN4(nds->pdu_scan_offset);
}
if ((outer_ref->ti->type_flags & NDR_F_FAKE) != 0 || n_pad == 0)
return (1);
if (!ndr_outer_grow(outer_ref, n_pad))
return (0);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
rc = NDS_PAD_PDU(nds, nds->pdu_scan_offset, n_pad, outer_ref);
if (!rc) {
NDR_SET_ERROR(outer_ref, NDR_ERR_PAD_FAILED);
return (0);
}
break;
case NDR_M_OP_UNMARSHALL:
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
nds->pdu_scan_offset += n_pad;
return (1);
}
int
ndr_outer_grow(ndr_ref_t *outer_ref, unsigned n_total)
{
ndr_stream_t *nds = outer_ref->stream;
unsigned long pdu_want_size;
int rc, is_ok = 0;
pdu_want_size = nds->pdu_scan_offset + n_total;
if (pdu_want_size <= nds->pdu_max_size) {
is_ok = 1;
}
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
if (is_ok)
break;
rc = NDS_GROW_PDU(nds, pdu_want_size, outer_ref);
if (!rc) {
NDR_SET_ERROR(outer_ref, NDR_ERR_GROW_FAILED);
return (0);
}
break;
case NDR_M_OP_UNMARSHALL:
if (is_ok)
break;
NDR_SET_ERROR(outer_ref, NDR_ERR_UNDERFLOW);
return (0);
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
if (nds->pdu_size < pdu_want_size)
nds->pdu_size = pdu_want_size;
outer_ref->pdu_end_offset = pdu_want_size;
return (1);
}
int
ndr_inner_align(ndr_ref_t *arg_ref)
{
ndr_stream_t *nds = arg_ref->stream;
int rc;
unsigned n_pad;
n_pad = ((arg_ref->ti->alignment + 1) - arg_ref->pdu_offset) &
arg_ref->ti->alignment;
if (n_pad == 0)
return (1);
if (!ndr_outer_grow(arg_ref->enclosing, n_pad))
return (0);
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
rc = NDS_PAD_PDU(nds, arg_ref->pdu_offset, n_pad, arg_ref);
if (!rc) {
NDR_SET_ERROR(arg_ref, NDR_ERR_PAD_FAILED);
return (0);
}
break;
case NDR_M_OP_UNMARSHALL:
break;
default:
NDR_SET_ERROR(arg_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
arg_ref->enclosing->pdu_offset += n_pad;
arg_ref->pdu_offset += n_pad;
nds->pdu_scan_offset += n_pad;
return (1);
}
int
ndr_inner(ndr_ref_t *arg_ref)
{
ndr_typeinfo_t *ti = arg_ref->ti;
int is_varlen = ti->pdu_size_variable_part;
int is_union = NDR_IS_UNION(ti);
int error = NDR_ERR_INNER_PARAMS_BAD;
int params;
params = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
if (arg_ref->enclosing != NULL &&
(arg_ref->enclosing->ti->type_flags & NDR_F_FAKE) != 0 &&
!ndr_inner_align(arg_ref))
return (0);
switch (params) {
case NDR_F_NONE:
if (is_union) {
error = NDR_ERR_SWITCH_VALUE_MISSING;
break;
}
return (*ti->ndr_func)(arg_ref);
case NDR_F_SIZE_IS:
case NDR_F_DIMENSION_IS:
case NDR_F_IS_POINTER+NDR_F_SIZE_IS:
case NDR_F_IS_REFERENCE+NDR_F_SIZE_IS:
if (is_varlen) {
error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
break;
}
if (is_union) {
error = NDR_ERR_ARRAY_UNION_ILLEGAL;
break;
}
if (params & NDR_F_IS_POINTER)
return (ndr_inner_pointer(arg_ref));
else if (params & NDR_F_IS_REFERENCE)
return (ndr_inner_reference(arg_ref));
else
return (ndr_inner_array(arg_ref));
case NDR_F_IS_POINTER:
if (is_union) {
error = NDR_ERR_ARRAY_UNION_ILLEGAL;
break;
}
return (ndr_inner_pointer(arg_ref));
case NDR_F_IS_REFERENCE:
if (is_union) {
error = NDR_ERR_ARRAY_UNION_ILLEGAL;
break;
}
return (ndr_inner_reference(arg_ref));
case NDR_F_SWITCH_IS:
if (!is_union) {
error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
break;
}
return (*ti->ndr_func)(arg_ref);
default:
error = NDR_ERR_INNER_PARAMS_BAD;
break;
}
NDR_SET_ERROR(arg_ref, error);
return (0);
}
int
ndr_inner_pointer(ndr_ref_t *arg_ref)
{
ndr_stream_t *nds = arg_ref->stream;
char **valpp = (char **)arg_ref->datum;
ndr_ref_t *outer_ref;
if (!ndr__ulong(arg_ref))
return (0);
if (!*valpp)
return (1);
outer_ref = ndr_enter_outer_queue(arg_ref);
if (!outer_ref)
return (0);
outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
#ifdef NDR_INNER_PTR_NOT_YET
outer_ref->outer_flags |= NDR_F_BACKPTR;
if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
}
#endif
outer_ref->backptr = valpp;
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
outer_ref->datum = *valpp;
break;
case NDR_M_OP_UNMARSHALL:
*valpp = 0;
outer_ref->datum = 0;
break;
}
return (1);
}
int
ndr_inner_reference(ndr_ref_t *arg_ref)
{
ndr_stream_t *nds = arg_ref->stream;
char **valpp = (char **)arg_ref->datum;
ndr_ref_t *outer_ref;
outer_ref = ndr_enter_outer_queue(arg_ref);
if (!outer_ref)
return (0);
outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
if ((outer_ref->outer_flags & NDR_F_SIZE_IS) == 0)
outer_ref->outer_flags &= ~NDR_F_IS_REFERENCE;
#ifdef NDR_INNER_REF_NOT_YET
outer_ref->outer_flags |= NDR_F_BACKPTR;
if (outer_ref->outer_flags & NDR_F_SIZE_IS) {
outer_ref->outer_flags |= NDR_F_ARRAY+NDR_F_CONFORMANT;
}
#endif
outer_ref->backptr = valpp;
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
outer_ref->datum = *valpp;
break;
case NDR_M_OP_UNMARSHALL:
*valpp = 0;
outer_ref->datum = 0;
break;
}
return (1);
}
int
ndr_inner_array(ndr_ref_t *encl_ref)
{
ndr_typeinfo_t *ti = encl_ref->ti;
ndr_ref_t myref;
unsigned long pdu_offset = encl_ref->pdu_offset;
unsigned long n_elem;
unsigned long i;
char name[30];
if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
if (!ndr_size_is(encl_ref))
return (0);
n_elem = encl_ref->size_is;
} else {
assert(encl_ref->inner_flags & NDR_F_DIMENSION_IS);
n_elem = encl_ref->dimension_is;
}
bzero(&myref, sizeof (myref));
myref.enclosing = encl_ref;
myref.stream = encl_ref->stream;
myref.packed_alignment = 0;
myref.ti = ti;
myref.inner_flags = NDR_F_NONE;
for (i = 0; i < n_elem; i++) {
(void) snprintf(name, sizeof (name), "[%lu]", i);
myref.name = name;
myref.pdu_offset = pdu_offset + i * ti->pdu_size_fixed_part;
myref.datum = encl_ref->datum + i * ti->c_size_fixed_part;
if (!ndr_inner(&myref))
return (0);
}
return (1);
}
#define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
extern int ndr_##TYPE(struct ndr_reference *encl_ref); \
ndr_typeinfo_t ndt_##TYPE = { \
1, \
(SIZE)-1, \
NDR_F_NONE, \
ndr_##TYPE, \
SIZE, \
0, \
SIZE, \
0, \
}; \
int ndr_##TYPE(struct ndr_reference *ref) { \
return (ndr_basic_integer(ref, SIZE)); \
}
#define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
extern int ndr_s##TYPE(struct ndr_reference *encl_ref); \
ndr_typeinfo_t ndt_s##TYPE = { \
1, \
(SIZE)-1, \
NDR_F_STRING, \
ndr_s##TYPE, \
0, \
SIZE, \
0, \
SIZE, \
}; \
int ndr_s##TYPE(struct ndr_reference *ref) { \
return (ndr_string_basic_integer(ref, &ndt_##TYPE)); \
}
#define MAKE_BASIC_TYPE(TYPE, SIZE) \
MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
int ndr_basic_integer(ndr_ref_t *, unsigned);
int ndr_string_basic_integer(ndr_ref_t *, ndr_typeinfo_t *);
MAKE_BASIC_TYPE(_char, 1)
MAKE_BASIC_TYPE(_uchar, 1)
MAKE_BASIC_TYPE(_short, 2)
MAKE_BASIC_TYPE(_ushort, 2)
MAKE_BASIC_TYPE(_long, 4)
MAKE_BASIC_TYPE(_ulong, 4)
MAKE_BASIC_TYPE_BASE(_wchar, 2)
int
ndr_basic_integer(ndr_ref_t *ref, unsigned size)
{
ndr_stream_t *nds = ref->stream;
char *valp = (char *)ref->datum;
int rc;
switch (nds->m_op) {
case NDR_M_OP_MARSHALL:
rc = NDS_PUT_PDU(nds, ref->pdu_offset, size,
valp, nds->swap, ref);
break;
case NDR_M_OP_UNMARSHALL:
rc = NDS_GET_PDU(nds, ref->pdu_offset, size,
valp, nds->swap, ref);
break;
default:
NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
return (0);
}
return (rc);
}
int
ndr_string_basic_integer(ndr_ref_t *encl_ref, ndr_typeinfo_t *type_under)
{
unsigned long pdu_offset = encl_ref->pdu_offset;
unsigned size = type_under->pdu_size_fixed_part;
char *valp;
ndr_ref_t myref;
unsigned long i;
long sense = 0;
char name[30];
assert(size != 0);
bzero(&myref, sizeof (myref));
myref.enclosing = encl_ref;
myref.stream = encl_ref->stream;
myref.packed_alignment = 0;
myref.ti = type_under;
myref.inner_flags = NDR_F_NONE;
myref.name = name;
for (i = 0; i < NDR_STRING_MAX; i++) {
(void) snprintf(name, sizeof (name), "[%lu]", i);
myref.pdu_offset = pdu_offset + i * size;
valp = encl_ref->datum + i * size;
myref.datum = valp;
if (!ndr_inner(&myref))
return (0);
switch (size) {
case 1: sense = *valp; break;
case 2: sense = *(short *)valp; break;
case 4: sense = *(long *)valp; break;
}
if (!sense)
break;
}
return (1);
}
extern int ndr_s_wchar(ndr_ref_t *encl_ref);
ndr_typeinfo_t ndt_s_wchar = {
1,
2-1,
NDR_F_STRING,
ndr_s_wchar,
0,
2,
0,
1,
};
int
ndr_s_wchar(ndr_ref_t *encl_ref)
{
ndr_stream_t *nds = encl_ref->stream;
char *valp = encl_ref->datum;
ndr_ref_t myref;
char name[30];
ndr_wchar_t wcs[NDR_STRING_MAX+1];
size_t i, slen, wlen;
assert(encl_ref->strlen_is <= NDR_STRING_MAX);
if (nds->m_op == NDR_M_OP_UNMARSHALL) {
if (encl_ref->strlen_is == 0) {
encl_ref->datum[0] = '\0';
return (1);
}
}
if (nds->m_op == NDR_M_OP_MARSHALL) {
wlen = ndr__mbstowcs(wcs, valp, NDR_STRING_MAX);
if (wlen == (size_t)-1)
return (0);
while (wlen < encl_ref->strlen_is)
wcs[wlen++] = 0;
wcs[wlen] = 0;
}
bzero(&myref, sizeof (myref));
myref.enclosing = encl_ref;
myref.stream = encl_ref->stream;
myref.packed_alignment = 0;
myref.ti = &ndt__wchar;
myref.inner_flags = NDR_F_NONE;
myref.name = name;
myref.pdu_offset = encl_ref->pdu_offset;
myref.datum = (char *)wcs;
wlen = encl_ref->strlen_is;
for (i = 0; i < wlen; i++) {
(void) snprintf(name, sizeof (name), "[%lu]", i);
if (!ndr_inner(&myref))
return (0);
myref.pdu_offset += sizeof (ndr_wchar_t);
myref.datum += sizeof (ndr_wchar_t);
}
if (nds->m_op == NDR_M_OP_UNMARSHALL) {
wcs[wlen] = 0;
slen = encl_ref->size_is * NDR_MB_CHAR_MAX;
slen = ndr__wcstombs(valp, wcs, slen);
if (slen == (size_t)-1)
return (0);
valp[slen] = '\0';
}
return (1);
}
size_t
ndr_mbstowcs(ndr_stream_t *nds, ndr_wchar_t *wcs, const char *mbs,
size_t nwchars)
{
size_t len;
#ifdef _BIG_ENDIAN
if (nds == NULL || NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) {
len = ndr__mbstowcs_le(wcs, mbs, nwchars);
} else
#endif
len = ndr__mbstowcs(wcs, mbs, nwchars);
return (len);
}