/* pull an array length field and add it to the array_length_list token list */ _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p) { uint32_t length, offset; NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset)); if (offset != 0) { return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "non-zero array offset %u\n", offset); } NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length)); return ndr_token_store(ndr, &ndr->array_length_list, p, length); }
/* parse a ref pointer referent identifier */ _PUBLIC_ enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v) { NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v)); /* ref pointers always point to data */ *v = 1; return NDR_ERR_SUCCESS; }
/* * Pull a DATA_BLOB from the wire. * 1) when called with LIBNDR_FLAG_ALIGN* alignment flags set, pull padding * bytes _only_. The length is determined by the alignment required and the * current ndr offset. * 2) When called with the LIBNDR_FLAG_REMAINING flag, pull all remaining bytes * from the ndr buffer. * 3) Otherwise, pull a uint3264 length _and_ a corresponding byte array from the * ndr buffer. */ _PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, int ndr_flags, DATA_BLOB *blob) { uint32_t length = 0; if (ndr->flags & LIBNDR_FLAG_REMAINING) { length = ndr->data_size - ndr->offset; } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) { if (ndr->flags & LIBNDR_FLAG_ALIGN2) { length = NDR_ALIGN(ndr, 2); } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { length = NDR_ALIGN(ndr, 4); } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { length = NDR_ALIGN(ndr, 8); } if (ndr->data_size - ndr->offset < length) { length = ndr->data_size - ndr->offset; } } else { NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length)); } NDR_PULL_NEED_BYTES(ndr, length); *blob = data_blob_talloc(ndr->current_mem_ctx, ndr->data+ndr->offset, length); ndr->offset += length; return NDR_ERR_SUCCESS; }
/* parse a pointer referent identifier */ _PUBLIC_ enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v) { NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v)); if (*v != 0) { ndr->ptr_count++; } return NDR_ERR_SUCCESS; }
/* parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field */ enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) { uint32_t num_auths; if (!(ndr_flags & NDR_SCALARS)) { return NDR_ERR_SUCCESS; } NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths)); NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid)); if (sid->num_auths != num_auths) { return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array size %u should exceed %u", num_auths, sid->num_auths); } return NDR_ERR_SUCCESS; }
/* pull an array size field and add it to the array_size_list token list */ _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p) { uint32_t size; NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size)); return ndr_token_store(ndr, &ndr->array_size_list, p, size); }
/* handle subcontext buffers, which in midl land are user-marshalled, but we use magic in pidl to make them easier to cope with */ _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr, struct ndr_pull **_subndr, size_t header_size, ssize_t size_is) { struct ndr_pull *subndr; uint32_t r_content_size; bool force_le = false; bool force_be = false; switch (header_size) { case 0: { uint32_t content_size = ndr->data_size - ndr->offset; if (size_is >= 0) { content_size = size_is; } r_content_size = content_size; break; } case 2: { uint16_t content_size; NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size)); if (size_is >= 0 && size_is != content_size) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", (int)size_is, (int)content_size); } r_content_size = content_size; break; } case 4: { uint32_t content_size; NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size)); if (size_is >= 0 && size_is != content_size) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", (int)size_is, (int)content_size); } r_content_size = content_size; break; } case 0xFFFFFC01: { /* * Common Type Header for the Serialization Stream * See [MS-RPCE] 2.2.6 Type Serialization Version 1 */ uint8_t version; uint8_t drep; uint16_t hdrlen; uint32_t filler; uint32_t content_size; uint32_t reserved; /* version */ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version)); if (version != 1) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) Common Type Header version %d != 1", (int)version); } /* * 0x10 little endian * 0x00 big endian */ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep)); if (drep == 0x10) { force_le = true; } else if (drep == 0x00) { force_be = true; } else { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X", (unsigned int)drep); } /* length of the "Private Header for Constructed Type" */ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen)); if (hdrlen != 8) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) Common Type Header length %d != 8", (int)hdrlen); } /* filler should be ignored */ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler)); /* * Private Header for Constructed Type */ /* length - will be updated latter */ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size)); if (size_is >= 0 && size_is != content_size) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", (int)size_is, (int)content_size); } /* the content size must be a multiple of 8 */ if ((content_size % 8) != 0) { return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d", (int)size_is, (int)content_size); } r_content_size = content_size; /* reserved */ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved)); break; } default: return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", (int)header_size); } NDR_PULL_NEED_BYTES(ndr, r_content_size); subndr = talloc_zero(ndr, struct ndr_pull); NDR_ERR_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->offset = 0; subndr->data_size = r_content_size; subndr->iconv_convenience = talloc_reference(subndr, ndr->iconv_convenience); if (force_le) { ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN); } else if (force_be) { ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN); } *_subndr = subndr; return NDR_ERR_SUCCESS; }