_PUBLIC_ enum ndr_err_code ndr_push_xattr_DOSATTRIB(struct ndr_push *ndr, int ndr_flags, const struct xattr_DOSATTRIB *r) { if (ndr_flags & NDR_SCALARS) { char *attrib_hex = NULL; attrib_hex = ndr_compat_xattr_attrib_hex(ndr, r); NDR_ERR_HAVE_NO_MEMORY(attrib_hex); NDR_CHECK(ndr_push_align(ndr, 4)); { uint32_t _flags_save_string = ndr->flags; ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM); NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, attrib_hex)); ndr->flags = _flags_save_string; } if (r->version == 0xFFFF) { return NDR_ERR_SUCCESS; } NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version)); NDR_CHECK(ndr_push_set_switch_value(ndr, &r->info, r->version)); NDR_CHECK(ndr_push_xattr_DosInfo(ndr, NDR_SCALARS, &r->info)); } if (ndr_flags & NDR_BUFFERS) { } return NDR_ERR_SUCCESS; }
/* parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth */ enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) { enum ndr_err_code status; struct ndr_pull *subndr; if (!(ndr_flags & NDR_SCALARS)) { return NDR_ERR_SUCCESS; } subndr = talloc_zero(ndr, struct ndr_pull); NDR_ERR_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags; subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->data_size = 28; subndr->offset = 0; NDR_CHECK(ndr_pull_advance(ndr, 28)); status = ndr_pull_dom_sid(subndr, ndr_flags, sid); if (!NDR_ERR_CODE_IS_SUCCESS(status)) { /* handle a w2k bug which send random data in the buffer */ ZERO_STRUCTP(sid); } else if (sid->num_auths == 0 && sid->sub_auths) { ZERO_STRUCT(sid->sub_auths); } return NDR_ERR_SUCCESS; }
/* pull a union from a blob using NDR, given the union discriminator, failing if all bytes are not consumed */ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; uint32_t highest_ofs; ndr = ndr_pull_init_blob(blob, mem_ctx); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level)); NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); if (ndr->offset > ndr->relative_highest_offset) { highest_ofs = ndr->offset; } else { highest_ofs = ndr->relative_highest_offset; } if (highest_ofs < ndr->data_size) { enum ndr_err_code ret; ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES, "not all bytes consumed ofs[%u] size[%u]", highest_ofs, ndr->data_size); talloc_free(ndr); return ret; } talloc_free(ndr); return NDR_ERR_SUCCESS; }
/* pull a ipv4address */ _PUBLIC_ enum ndr_err_code ndr_pull_ipv4address(struct ndr_pull *ndr, int ndr_flags, const char **address) { struct in_addr in; NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &in.s_addr)); in.s_addr = htonl(in.s_addr); *address = talloc_strdup(ndr->current_mem_ctx, inet_ntoa(in)); NDR_ERR_HAVE_NO_MEMORY(*address); return NDR_ERR_SUCCESS; }
/* pull a struct from a blob using NDR */ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p, ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); talloc_free(ndr); return NDR_ERR_SUCCESS; }
/* pull a union from a blob using NDR, given the union discriminator */ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level)); NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); talloc_free(ndr); return NDR_ERR_SUCCESS; }
/* store a token in the ndr context, for later retrieval */ _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, struct ndr_token_list **list, const void *key, uint32_t value) { struct ndr_token_list *tok; tok = talloc(mem_ctx, struct ndr_token_list); NDR_ERR_HAVE_NO_MEMORY(tok); tok->key = key; tok->value = value; DLIST_ADD((*list), tok); return NDR_ERR_SUCCESS; }
/* push a struct to a blob using NDR */ _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const void *p, ndr_push_flags_fn_t fn) { struct ndr_push *ndr; ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); *blob = ndr_push_blob(ndr); talloc_steal(mem_ctx, blob->data); talloc_free(ndr); return NDR_ERR_SUCCESS; }
_PUBLIC_ enum ndr_err_code ndr_pull_AuthenticationInformationArray(struct ndr_pull *ndr, int ndr_flags, struct AuthenticationInformationArray *r) { if (ndr_flags & NDR_SCALARS) { r->count = 0; NDR_PULL_ALLOC_N(ndr, r->array, r->count); /* entry is at least 16 bytes large */ while (ndr->offset + 16 <= ndr->data_size) { r->array = talloc_realloc(ndr, r->array, struct AuthenticationInformation, r->count + 1); NDR_ERR_HAVE_NO_MEMORY(r->array); NDR_CHECK(ndr_pull_AuthenticationInformation(ndr, NDR_SCALARS, &r->array[r->count])); r->count++; } NDR_CHECK(ndr_pull_align(ndr, 4)); }
/* pull a struct from a blob using NDR - failing if all bytes are not consumed */ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p, ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); if (ndr->offset < ndr->data_size) { return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES, "not all bytes consumed ofs[%u] size[%u]", ndr->offset, ndr->data_size); } talloc_free(ndr); return NDR_ERR_SUCCESS; }
static enum ndr_err_code torture_ndr_push_struct_blob_flags(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32_t flags, uint32_t ndr_flags, const void *p, ndr_push_flags_fn_t fn) { struct ndr_push *ndr; ndr = ndr_push_init_ctx(mem_ctx); NDR_ERR_HAVE_NO_MEMORY(ndr); ndr->flags |= ndr_flags; NDR_CHECK(fn(ndr, flags, p)); *blob = ndr_push_blob(ndr); talloc_steal(mem_ctx, blob->data); talloc_free(ndr); return NDR_ERR_SUCCESS; }
/* push a union to a blob using NDR */ _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_push_flags_fn_t fn) { struct ndr_push *ndr; ndr = ndr_push_init_ctx(mem_ctx); NDR_ERR_HAVE_NO_MEMORY(ndr); NDR_CHECK(ndr_push_set_switch_value(ndr, p, level)); NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); *blob = ndr_push_blob(ndr); talloc_steal(mem_ctx, blob->data); talloc_free(ndr); return NDR_ERR_SUCCESS; }
_PUBLIC_ enum ndr_err_code ndr_pull_ipv6address(struct ndr_pull *ndr, int ndr_flags, const char **address) { uint8_t addr[IPV6_BYTES]; char *addr_str = talloc_strdup(ndr->current_mem_ctx, ""); int i; NDR_CHECK(ndr_pull_array_uint8(ndr, ndr_flags, addr, IPV6_BYTES)); for (i = 0; i < IPV6_BYTES; ++i) { addr_str = talloc_asprintf_append(addr_str, "%02x", addr[i]); /* We need a ':' every second byte but the last one */ if (i%2 == 1 && i != (IPV6_BYTES - 1)) { addr_str = talloc_strdup_append(addr_str, ":"); } } *address = addr_str; NDR_ERR_HAVE_NO_MEMORY(*address); return NDR_ERR_SUCCESS; }
_PUBLIC_ enum ndr_err_code ndr_pull_ntprinting_printer(struct ndr_pull *ndr, int ndr_flags, struct ntprinting_printer *r) { uint32_t _ptr_devmode; TALLOC_CTX *_mem_save_devmode_0; { uint32_t _flags_save_STRUCT = ndr->flags; ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); if (ndr_flags & NDR_SCALARS) { NDR_CHECK(ndr_pull_align(ndr, 5)); NDR_CHECK(ndr_pull_ntprinting_printer_info(ndr, NDR_SCALARS, &r->info)); NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_devmode)); if (_ptr_devmode) { NDR_PULL_ALLOC(ndr, r->devmode); } else { r->devmode = NULL; } } if (ndr_flags & NDR_BUFFERS) { if (r->devmode) { _mem_save_devmode_0 = NDR_PULL_GET_MEM_CTX(ndr); NDR_PULL_SET_MEM_CTX(ndr, r->devmode, 0); NDR_CHECK(ndr_pull_ntprinting_devicemode(ndr, NDR_SCALARS|NDR_BUFFERS, r->devmode)); NDR_PULL_SET_MEM_CTX(ndr, _mem_save_devmode_0, 0); } } if (ndr_flags & NDR_SCALARS) { r->count = 0; NDR_PULL_ALLOC_N(ndr, r->printer_data, r->count); while (ndr->offset + 4 <= ndr->data_size) { uint32_t ptr = 0; ptr = IVAL(ndr->data, ndr->offset); if (ptr == 0) { break; } r->printer_data = talloc_realloc(ndr, r->printer_data, struct ntprinting_printer_data, r->count + 1); NDR_ERR_HAVE_NO_MEMORY(r->printer_data); NDR_CHECK(ndr_pull_ntprinting_printer_data(ndr, NDR_SCALARS, &r->printer_data[r->count])); r->count++; } NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); } ndr->flags = _flags_save_STRUCT; }
_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr, struct ndr_push **_subndr, size_t header_size, ssize_t size_is) { struct ndr_push *subndr; subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; if (size_is > 0) { NDR_CHECK(ndr_push_zero(subndr, size_is)); subndr->offset = 0; subndr->relative_end_offset = size_is; } *_subndr = subndr; return NDR_ERR_SUCCESS; }
/* 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; }