#include <strings.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <libmlrpc/ndr.h>
#include <libmlrpc/mlrpc.h>
#define NDR_STRING_MAX 256
#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 struct ndr_typeinfo ndt_s_wchar;
static struct ndr_reference *mlndr_enter_outer_queue(struct ndr_reference *);
extern int mlndr__uint32_t(struct ndr_reference *);
int
mlndo_process(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
char *datum)
{
struct ndr_reference myref;
bzero(&myref, sizeof (myref));
myref.stream = mlnds;
myref.datum = datum;
myref.name = "PROCESS";
myref.ti = ti;
return (mlndr_topmost(&myref));
}
int
mlndo_operation(struct mlndr_stream *mlnds, struct ndr_typeinfo *ti,
int opnum, char *datum)
{
struct ndr_reference myref;
bzero(&myref, sizeof (myref));
myref.stream = mlnds;
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
mlndr_params(struct ndr_reference *params_ref)
{
struct ndr_typeinfo *ti = params_ref->ti;
if (ti->type_flags == NDR_F_OPERATION)
return (*ti->ndr_func) (params_ref);
else
return (mlndr_topmost(params_ref));
}
int
mlndr_topmost(struct ndr_reference *top_ref)
{
struct mlndr_stream *mlnds;
struct ndr_typeinfo *ti;
struct ndr_reference *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);
mlnds = top_ref->stream;
ti = top_ref->ti;
is_varlen = ti->pdu_size_variable_part;
is_string = NDR_IS_STRING(ti);
assert(mlnds->outer_queue_tailp && !*mlnds->outer_queue_tailp);
assert(!mlnds->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 = mlndr_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 (!mlndr_outer_align(outer_ref))
return (0);
outer_ref->pdu_offset = mlnds->pdu_scan_offset;
rc = mlndr_outer_grow(outer_ref, n_fixed);
if (!rc)
return (0);
outer_ref->pdu_end_offset = outer_ref->pdu_offset + n_fixed;
mlnds->outer_current = outer_ref;
mlnds->outer_queue_tailp = &mlnds->outer_current->next;
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
rc = mlndr_inner(outer_ref);
if (!rc)
return (0);
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
mlnds->outer_current = mlnds->outer_current->next;
return (mlndr_run_outer_queue(mlnds));
}
static struct ndr_reference *
mlndr_enter_outer_queue(struct ndr_reference *arg_ref)
{
struct mlndr_stream *mlnds = arg_ref->stream;
struct ndr_reference *outer_ref;
outer_ref = (struct ndr_reference *)
MLNDS_MALLOC(mlnds, 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 = mlnds->outer_current;
outer_ref->backptr = 0;
outer_ref->datum = 0;
assert(mlnds->outer_queue_tailp);
outer_ref->next = *mlnds->outer_queue_tailp;
*mlnds->outer_queue_tailp = outer_ref;
mlnds->outer_queue_tailp = &outer_ref->next;
return (outer_ref);
}
int
mlndr_run_outer_queue(struct mlndr_stream *mlnds)
{
while (mlnds->outer_current) {
mlnds->outer_queue_tailp = &mlnds->outer_current->next;
if (!mlndr_outer(mlnds->outer_current))
return (0);
mlnds->outer_current = mlnds->outer_current->next;
}
return (1);
}
int
mlndr_outer(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *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 (!mlndr_outer_align(outer_ref))
return (0);
outer_ref->pdu_offset = mlnds->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 (mlndr_outer_string(outer_ref));
if (is_varlen)
return (mlndr_outer_conformant_construct(outer_ref));
return (mlndr_outer_fixed(outer_ref));
break;
case NDR_F_SIZE_IS:
case NDR_F_DIMENSION_IS:
if (is_varlen) {
error = NDR_ERR_ARRAY_VARLEN_ILLEGAL;
break;
}
if (params == NDR_F_SIZE_IS)
return (mlndr_outer_conformant_array(outer_ref));
else
return (mlndr_outer_fixed_array(outer_ref));
break;
default:
error = NDR_ERR_OUTER_PARAMS_BAD;
break;
}
NDR_SET_ERROR(outer_ref, error);
return (0);
}
int
mlndr_outer_fixed(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *ti = outer_ref->ti;
struct ndr_reference 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 = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
assert(valp);
if (outer_ref->backptr) {
assert(valp == *outer_ref->backptr);
}
break;
case NDR_M_OP_UNMARSHALL:
valp = MLNDS_MALLOC(mlnds, 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 = mlnds;
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 = mlndr_inner(&myref);
if (!rc)
return (rc);
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
mlndr_outer_fixed_array(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *ti = outer_ref->ti;
struct ndr_reference 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 = (ti->c_size_fixed_part * outer_ref->dimension_is) + n_variable;
rc = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
assert(valp);
if (outer_ref->backptr) {
assert(valp == *outer_ref->backptr);
}
break;
case NDR_M_OP_UNMARSHALL:
valp = MLNDS_MALLOC(mlnds, 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 = mlnds;
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 = mlndr_inner(&myref);
if (!rc)
return (rc);
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
mlndr_outer_conformant_array(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *ti = outer_ref->ti;
struct ndr_reference 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);
uint32_t 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_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 = (ti->c_size_fixed_part * outer_ref->size_is) + n_fixed;
rc = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
size_is = outer_ref->size_is;
rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
valp = outer_ref->datum;
assert(valp);
if (outer_ref->backptr) {
assert(valp == *outer_ref->backptr);
}
break;
case NDR_M_OP_UNMARSHALL:
rc = mlndr_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);
}
valp = MLNDS_MALLOC(mlnds, 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 = mlnds;
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 + 4;
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;
rc = mlndr_inner(&myref);
if (!rc)
return (rc);
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
mlndr_outer_conformant_construct(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *ti = outer_ref->ti;
struct ndr_reference 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);
uint32_t 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 = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
size_is = 0;
rc = mlndr_outer_poke_sizing(outer_ref, 0, &size_is);
if (!rc)
return (0);
valp = outer_ref->datum;
assert(valp);
if (outer_ref->backptr) {
assert(valp == *outer_ref->backptr);
}
break;
case NDR_M_OP_UNMARSHALL:
rc = mlndr_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 = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
outer_ref->size_is = size_is;
valp = MLNDS_MALLOC(mlnds, 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 = mlnds;
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;
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;
rc = mlndr_inner(&myref);
if (!rc)
return (rc);
mlnds->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
mlndr_size_is(struct ndr_reference *ref)
{
struct mlndr_stream *mlnds = ref->stream;
struct ndr_reference *outer_ref = mlnds->outer_current;
struct ndr_typeinfo *ti = outer_ref->ti;
uint32_t 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 = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
rc = mlndr_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
mlndr_outer_string(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = outer_ref->stream;
struct ndr_typeinfo *ti = outer_ref->ti;
struct ndr_reference 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;
uint32_t size_is;
uint32_t first_is;
uint32_t 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 (!mlndr_outer_grow(outer_ref, n_hdr))
return (0);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
valp = outer_ref->datum;
assert(valp);
if (outer_ref->backptr)
assert(valp == *outer_ref->backptr);
if (ti == &ndt_s_wchar) {
size_is = (mts_wcequiv_strlen(valp) /
sizeof (mts_wchar_t)) + 1;
if (size_is > NDR_STRING_MAX) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
} else {
valp = outer_ref->datum;
n_zeroes = 0;
for (ix = 0; ix < 1024; ix++) {
if (valp[ix] == 0) {
n_zeroes++;
if (n_zeroes >= is_varlen &&
ix % is_varlen == 0) {
break;
}
} else {
n_zeroes = 0;
}
}
if (ix >= 1024) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN);
return (0);
}
size_is = ix+1;
}
first_is = 0;
if (mlnds->flags & MLNDS_F_NOTERM)
length_is = size_is - 1;
else
length_is = size_is;
if (!mlndr_outer_poke_sizing(outer_ref, 0, &size_is) ||
!mlndr_outer_poke_sizing(outer_ref, 4, &first_is) ||
!mlndr_outer_poke_sizing(outer_ref, 8, &length_is))
return (0);
break;
case NDR_M_OP_UNMARSHALL:
if (!mlndr_outer_peek_sizing(outer_ref, 0, &size_is) ||
!mlndr_outer_peek_sizing(outer_ref, 4, &first_is) ||
!mlndr_outer_peek_sizing(outer_ref, 8, &length_is))
return (0);
if (first_is != 0) {
NDR_SET_ERROR(outer_ref, NDR_ERR_STRING_SIZING);
return (0);
}
if (ti == &ndt_s_wchar) {
n_alloc = (size_is + 1) * MTS_MB_CHAR_MAX;
} else {
n_alloc = (size_is + 1) * is_varlen;
}
valp = MLNDS_MALLOC(mlnds, 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 = mlndr_outer_grow(outer_ref, n_pdu_total);
if (!rc)
return (rc);
if (length_is > 0) {
bzero(&myref, sizeof (myref));
myref.stream = mlnds;
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)) {
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
if ((size_is != 0) && (length_is != 0)) {
rc = mlndr_inner(&myref);
if (!rc)
return (rc);
}
mlnds->pdu_scan_offset = outer_ref->pdu_end_offset;
return (1);
}
int
mlndr_outer_peek_sizing(struct ndr_reference *outer_ref, unsigned offset,
uint32_t *sizing_p)
{
struct mlndr_stream *mlnds = outer_ref->stream;
unsigned long pdu_offset;
int rc;
pdu_offset = outer_ref->pdu_offset + offset;
if (pdu_offset < mlnds->outer_current->pdu_offset ||
pdu_offset > mlnds->outer_current->pdu_end_offset ||
pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
return (0);
}
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
NDR_SET_ERROR(outer_ref, NDR_ERR_UNIMPLEMENTED);
return (0);
case NDR_M_OP_UNMARSHALL:
rc = MLNDS_GET_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
mlnds->swap, outer_ref);
break;
default:
NDR_SET_ERROR(outer_ref, NDR_ERR_M_OP_INVALID);
return (0);
}
return (rc);
}
int
mlndr_outer_poke_sizing(struct ndr_reference *outer_ref, unsigned offset,
uint32_t *sizing_p)
{
struct mlndr_stream *mlnds = outer_ref->stream;
unsigned long pdu_offset;
int rc;
pdu_offset = outer_ref->pdu_offset + offset;
if (pdu_offset < mlnds->outer_current->pdu_offset ||
pdu_offset > mlnds->outer_current->pdu_end_offset ||
pdu_offset+4 > mlnds->outer_current->pdu_end_offset) {
NDR_SET_ERROR(outer_ref, NDR_ERR_BOUNDS_CHECK);
return (0);
}
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
rc = MLNDS_PUT_PDU(mlnds, pdu_offset, 4, (char *)sizing_p,
mlnds->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
mlndr_outer_align(struct ndr_reference *outer_ref)
{
struct mlndr_stream *mlnds = 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) - mlnds->pdu_scan_offset) & align;
} else {
n_pad = (4 - mlnds->pdu_scan_offset) & 3;
}
if (n_pad == 0)
return (1);
if (!mlndr_outer_grow(outer_ref, n_pad))
return (0);
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
rc = MLNDS_PAD_PDU(mlnds,
mlnds->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);
}
mlnds->pdu_scan_offset += n_pad;
return (1);
}
int
mlndr_outer_grow(struct ndr_reference *outer_ref, unsigned n_total)
{
struct mlndr_stream *mlnds = outer_ref->stream;
uint32_t pdu_want_size;
int rc, is_ok = 0;
pdu_want_size = mlnds->pdu_scan_offset + n_total;
if (pdu_want_size <= mlnds->pdu_max_size) {
is_ok = 1;
}
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
if (is_ok)
break;
rc = MLNDS_GROW_PDU(mlnds, 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 (mlnds->pdu_size < pdu_want_size)
mlnds->pdu_size = pdu_want_size;
outer_ref->pdu_end_offset = pdu_want_size;
return (1);
}
int
mlndr_inner(struct ndr_reference *arg_ref)
{
struct ndr_typeinfo *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;
switch (params) {
case NDR_F_NONE:
if (is_union) {
error = NDR_ERR_SWITCH_VALUE_MISSING;
break;
}
return (*ti->ndr_func)(arg_ref);
break;
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 (mlndr_inner_pointer(arg_ref));
else if (params & NDR_F_IS_REFERENCE)
return (mlndr_inner_reference(arg_ref));
else
return (mlndr_inner_array(arg_ref));
break;
case NDR_F_IS_POINTER:
if (is_union) {
error = NDR_ERR_ARRAY_UNION_ILLEGAL;
break;
}
return (mlndr_inner_pointer(arg_ref));
break;
case NDR_F_IS_REFERENCE:
if (is_union) {
error = NDR_ERR_ARRAY_UNION_ILLEGAL;
break;
}
return (mlndr_inner_reference(arg_ref));
break;
case NDR_F_SWITCH_IS:
if (!is_union) {
error = NDR_ERR_SWITCH_VALUE_ILLEGAL;
break;
}
return (*ti->ndr_func)(arg_ref);
break;
default:
error = NDR_ERR_INNER_PARAMS_BAD;
break;
}
NDR_SET_ERROR(arg_ref, error);
return (0);
}
int
mlndr_inner_pointer(struct ndr_reference *arg_ref)
{
struct mlndr_stream *mlnds = arg_ref->stream;
char **valpp = (char **)arg_ref->datum;
struct ndr_reference *outer_ref;
if (!mlndr__uint32_t(arg_ref))
return (0);
if (!*valpp)
return (1);
outer_ref = mlndr_enter_outer_queue(arg_ref);
if (!outer_ref)
return (0);
outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
outer_ref->outer_flags &= ~NDR_F_IS_POINTER;
#ifdef NDR_INNER_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 (mlnds->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
mlndr_inner_reference(struct ndr_reference *arg_ref)
{
struct mlndr_stream *mlnds = arg_ref->stream;
char **valpp = (char **)arg_ref->datum;
struct ndr_reference *outer_ref;
outer_ref = mlndr_enter_outer_queue(arg_ref);
if (!outer_ref)
return (0);
outer_ref->outer_flags = arg_ref->inner_flags & NDR_F_PARAMS_MASK;
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 (mlnds->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
mlndr_inner_array(struct ndr_reference *encl_ref)
{
struct ndr_typeinfo *ti = encl_ref->ti;
struct ndr_reference myref;
uint32_t pdu_offset = encl_ref->pdu_offset;
uint32_t n_elem;
char name[30];
if (encl_ref->inner_flags & NDR_F_SIZE_IS) {
if (!mlndr_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 (unsigned i = 0; i < n_elem; i++) {
(void) snprintf(name, sizeof(name), "[%u]", 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 (!mlndr_inner(&myref))
return (0);
}
return (1);
}
#define MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
extern int mlndr_##TYPE(struct ndr_reference *encl_ref); \
struct ndr_typeinfo ndt_##TYPE = { \
#TYPE, \
1, \
(SIZE)-1, \
NDR_F_NONE, \
mlndr_##TYPE, \
SIZE, \
0, \
SIZE, \
0, \
}; \
int mlndr_##TYPE(struct ndr_reference *ref) { \
return (mlndr_basic_integer(ref, SIZE)); \
}
#define MAKE_BASIC_TYPE_STRING(TYPE, SIZE) \
extern int mlndr_s##TYPE(struct ndr_reference *encl_ref); \
struct ndr_typeinfo ndt_s##TYPE = { \
"s_"#TYPE, \
1, \
(SIZE)-1, \
NDR_F_STRING, \
mlndr_s##TYPE, \
0, \
SIZE, \
0, \
SIZE, \
}; \
int mlndr_s##TYPE(struct ndr_reference *ref) { \
return (mlndr_string_basic_integer(ref, &ndt_##TYPE)); \
}
#define MAKE_BASIC_TYPE(TYPE, SIZE) \
MAKE_BASIC_TYPE_BASE(TYPE, SIZE) \
MAKE_BASIC_TYPE_STRING(TYPE, SIZE)
extern int
mlndr_basic_integer(struct ndr_reference *ref, unsigned size);
extern int
mlndr_string_basic_integer(struct ndr_reference *encl_ref,
struct ndr_typeinfo *type_under);
MAKE_BASIC_TYPE(_char, 1)
MAKE_BASIC_TYPE(_uchar, 1)
MAKE_BASIC_TYPE(_int8_t, 1)
MAKE_BASIC_TYPE(_uint8_t, 1)
MAKE_BASIC_TYPE(_int16_t, 2)
MAKE_BASIC_TYPE(_uint16_t, 2)
MAKE_BASIC_TYPE(_int32_t, 4)
MAKE_BASIC_TYPE(_uint32_t, 4)
MAKE_BASIC_TYPE(_int64_t, 8)
MAKE_BASIC_TYPE(_uint64_t, 8)
MAKE_BASIC_TYPE_BASE(_wchar, 2)
int
mlndr_basic_integer(struct ndr_reference *ref, unsigned size)
{
struct mlndr_stream *mlnds = ref->stream;
char *valp = (char *)ref->datum;
int rc;
switch (mlnds->m_op) {
case NDR_M_OP_MARSHALL:
rc = MLNDS_PUT_PDU(mlnds, ref->pdu_offset, size,
valp, mlnds->swap, ref);
break;
case NDR_M_OP_UNMARSHALL:
rc = MLNDS_GET_PDU(mlnds, ref->pdu_offset, size,
valp, mlnds->swap, ref);
break;
default:
NDR_SET_ERROR(ref, NDR_ERR_M_OP_INVALID);
return (0);
}
return (rc);
}
int
mlndr_string_basic_integer(struct ndr_reference *encl_ref,
struct ndr_typeinfo *type_under)
{
unsigned long pdu_offset = encl_ref->pdu_offset;
unsigned size = type_under->pdu_size_fixed_part;
char *valp;
struct ndr_reference myref;
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 (unsigned i = 0; i < NDR_STRING_MAX; i++) {
(void) snprintf(name, sizeof(name), "[%u]", i);
myref.pdu_offset = pdu_offset + i * size;
valp = encl_ref->datum + i * size;
myref.datum = valp;
if (!mlndr_inner(&myref))
return (0);
switch (size) {
case 1: sense = *valp; break;
case 2: sense = *(uint16_t *)valp; break;
case 4: sense = *(uint32_t *)valp; break;
}
if (!sense)
break;
}
return (1);
}
extern int mlndr_s_wchar(struct ndr_reference *encl_ref);
struct ndr_typeinfo ndt_s_wchar = {
"s_wchar",
1,
2-1,
NDR_F_STRING,
mlndr_s_wchar,
0,
2,
0,
1,
};
int
mlndr_s_wchar(struct ndr_reference *encl_ref)
{
struct mlndr_stream *mlnds = encl_ref->stream;
unsigned short wide_char;
char *valp;
struct ndr_reference myref;
char name[30];
int count;
int char_count = 0;
if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
if (encl_ref->strlen_is == 0) {
encl_ref->datum[0] = '\0';
return (1);
}
}
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.datum = (char *)&wide_char;
myref.name = name;
myref.pdu_offset = encl_ref->pdu_offset;
valp = encl_ref->datum;
count = 0;
for (unsigned i = 0; i < NDR_STRING_MAX; i++) {
(void) snprintf(name, sizeof(name), "[%u]", i);
if (mlnds->m_op == NDR_M_OP_MARSHALL) {
count = mts_mbtowc((mts_wchar_t *)&wide_char, valp,
MTS_MB_CHAR_MAX);
if (count < 0) {
return (0);
} else if (count == 0) {
if (encl_ref->strlen_is != encl_ref->size_is)
break;
wide_char = *valp;
count = 1;
}
}
if (!mlndr_inner(&myref))
return (0);
if (mlnds->m_op == NDR_M_OP_UNMARSHALL) {
count = mts_wctomb(valp, wide_char);
if ((++char_count) == encl_ref->strlen_is) {
valp += count;
*valp = '\0';
break;
}
}
if (!wide_char)
break;
myref.pdu_offset += sizeof (wide_char);
valp += count;
}
return (1);
}
size_t
ndr_mbstowcs(struct mlndr_stream *mlnds, mts_wchar_t *wcs, const char *mbs,
size_t nwchars)
{
mts_wchar_t *start = wcs;
int nbytes;
while (nwchars--) {
nbytes = ndr_mbtowc(mlnds, wcs, mbs, MTS_MB_CHAR_MAX);
if (nbytes < 0) {
*wcs = 0;
return ((size_t)-1);
}
if (*mbs == 0)
break;
++wcs;
mbs += nbytes;
}
return (wcs - start);
}
int
ndr_mbtowc(struct mlndr_stream *mlnds, mts_wchar_t *wcharp,
const char *mbchar, size_t nbytes)
{
int rc;
if ((rc = mts_mbtowc(wcharp, mbchar, nbytes)) < 0)
return (rc);
if (mlrpc_native_byte_order == MLRPC_REPLAB_INTG_BIG_ENDIAN) {
if (mlnds == NULL ||
NDR_MODE_MATCH(mlnds, NDR_MODE_RETURN_SEND)) {
*wcharp = OSSwapInt16(*wcharp);
}
}
return (rc);
}