X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=librpc%2Fndr%2Fndr.c;h=61745aa55acabcb83f637efba36f95e3d0f91634;hb=4a76d29374769ba4c075b8d5767498848d2e17d6;hp=9f7aab3c03d3633b1c1365f9b0c27cc6c4bc95ef;hpb=bae593bb118459c1b0d12d02e58ba6c89400aa97;p=abartlet%2Fsamba.git%2F.git diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index 9f7aab3c03d..61745aa55ac 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -179,10 +179,10 @@ _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, } for (i=0;idepth;i++) { - DEBUGADD(0,(" ")); + DEBUGADD(1,(" ")); } - DEBUGADD(0,("%s\n", s)); + DEBUGADD(1,("%s\n", s)); free(s); } @@ -211,7 +211,7 @@ _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr) { struct ndr_print *ndr; - DEBUG(0,("")); + DEBUG(1,(" ")); ndr = talloc_zero(NULL, struct ndr_print); if (!ndr) return; @@ -229,7 +229,7 @@ _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_ { struct ndr_print *ndr; - DEBUG(0,("")); + DEBUG(1,(" ")); ndr = talloc_zero(NULL, struct ndr_print); if (!ndr) return; @@ -248,13 +248,21 @@ _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name { struct ndr_print *ndr; - DEBUG(0,("")); + DEBUG(1,(" ")); ndr = talloc_zero(NULL, struct ndr_print); if (!ndr) return; ndr->print = ndr_print_debug_helper; ndr->depth = 1; ndr->flags = 0; + + /* this is a s4 hack until we build up the courage to pass + * this all the way down + */ +#if _SAMBA_BUILD_ == 4 + ndr->iconv_convenience = smb_iconv_convenience_init(talloc_autofree_context(), "ASCII", "UTF-8", true); +#endif + fn(ndr, name, flags, ptr); talloc_free(ndr); } @@ -276,6 +284,14 @@ _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, c ndr->print = ndr_print_string_helper; ndr->depth = 1; ndr->flags = 0; + + /* this is a s4 hack until we build up the courage to pass + * this all the way down + */ +#if _SAMBA_BUILD_ == 4 + ndr->iconv_convenience = smb_iconv_convenience_init(talloc_autofree_context(), "ASCII", "UTF-8", true); +#endif + fn(ndr, name, ptr); ret = talloc_steal(mem_ctx, (char *)ndr->private_data); failed: @@ -339,9 +355,11 @@ _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags) /* the big/little endian flags are inter-dependent */ if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) { (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN; + (*pflags) &= ~LIBNDR_FLAG_NDR64; } if (new_flags & LIBNDR_FLAG_BIGENDIAN) { (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN; + (*pflags) &= ~LIBNDR_FLAG_NDR64; } if (new_flags & LIBNDR_FLAG_REMAINING) { (*pflags) &= ~LIBNDR_ALIGN_FLAGS; @@ -349,6 +367,9 @@ _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags) if (new_flags & LIBNDR_ALIGN_FLAGS) { (*pflags) &= ~LIBNDR_FLAG_REMAINING; } + if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) { + (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE; + } (*pflags) |= new_flags; } @@ -441,7 +462,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr, case 4: { uint32_t content_size; - NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &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); @@ -526,7 +547,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr, subndr = talloc_zero(ndr, struct ndr_pull); NDR_ERR_HAVE_NO_MEMORY(subndr); - subndr->flags = ndr->flags; + subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; @@ -570,7 +591,13 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr, subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(subndr); - subndr->flags = ndr->flags; + 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; @@ -588,12 +615,11 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr, if (size_is >= 0) { padding_len = size_is - subndr->offset; - if (padding_len > 0) { - NDR_CHECK(ndr_push_zero(subndr, padding_len)); - } else if (padding_len < 0) { + if (padding_len < 0) { return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)", (int)subndr->offset, (int)size_is); } + subndr->offset = size_is; } switch (header_size) { @@ -605,7 +631,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr, break; case 4: - NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset)); + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset)); break; case 0xFFFFFC01: @@ -720,7 +746,7 @@ _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key) _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p) { uint32_t size; - NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size)); + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size)); return ndr_token_store(ndr, &ndr->array_size_list, p, size); } @@ -753,12 +779,12 @@ _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, u _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p) { uint32_t length, offset; - NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &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_uint32(ndr, NDR_SCALARS, &length)); + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length)); return ndr_token_store(ndr, &ndr->array_length_list, p, length); } @@ -830,7 +856,8 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CT struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); - NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + talloc_free(ndr); return NDR_ERR_SUCCESS; } @@ -842,14 +869,24 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLO void *p, ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; + uint32_t highest_ofs; ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); - NDR_CHECK(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); + 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; } @@ -863,8 +900,9 @@ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); - NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level)); - NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + 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; } @@ -877,15 +915,25 @@ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC 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, iconv_convenience); NDR_ERR_HAVE_NO_MEMORY(ndr); - NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level)); - NDR_CHECK(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); + 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; } @@ -1033,11 +1081,25 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const vo return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF); } +/* + push a short relative object - stage1 + this is called during SCALARS processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p) +{ + if (p == NULL) { + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0)); + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_align(ndr, 2)); + NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset)); + return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF); +} /* push a relative object - stage2 this is called during buffers processing */ -_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p) +static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p) { uint32_t save_offset; uint32_t ptr_offset = 0xFFFFFFFF; @@ -1061,6 +1123,149 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const vo ndr->offset = save_offset; return NDR_ERR_SUCCESS; } +/* + push a short relative object - stage2 + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p) +{ + uint32_t save_offset; + uint32_t ptr_offset = 0xFFFF; + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + save_offset = ndr->offset; + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset)); + if (ptr_offset > ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)", + ptr_offset, ndr->offset); + } + ndr->offset = ptr_offset; + if (save_offset < ndr->relative_base_offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)", + save_offset, ndr->relative_base_offset); + } + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset)); + ndr->offset = save_offset; + return NDR_ERR_SUCCESS; +} + +/* + push a relative object - stage2 start + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p) +{ + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { + return ndr_push_relative_ptr2(ndr, p); + } + if (ndr->relative_end_offset == -1) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d", + ndr->relative_end_offset); + } + NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset)); + return NDR_ERR_SUCCESS; +} + +/* + push a relative object - stage2 end + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p) +{ + uint32_t begin_offset = 0xFFFFFFFF; + ssize_t len; + uint32_t correct_offset = 0; + uint32_t align = 1; + uint32_t pad = 0; + + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + + if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { + return NDR_ERR_SUCCESS; + } + + if (ndr->relative_end_offset < ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %u < offset %u", + ndr->relative_end_offset, ndr->offset); + } + + NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset)); + + /* we have marshalled a buffer, see how long it was */ + len = ndr->offset - begin_offset; + + if (len < 0) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "offset %u - begin_offset %u < 0", + ndr->offset, begin_offset); + } + + if (ndr->relative_end_offset < len) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %u < len %lld", + ndr->offset, (long long)len); + } + + /* the reversed offset is at the end of the main buffer */ + correct_offset = ndr->relative_end_offset - len; + + /* TODO: remove this hack and let the idl use FLAG_ALIGN2 explicit */ + align = 2; + + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + align = 2; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + align = 4; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + align = 8; + } + + pad = ndr_align_size(correct_offset, align); + if (pad) { + correct_offset += pad; + correct_offset -= align; + } + + if (correct_offset < begin_offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end: " + "correct_offset %u < begin_offset %u", + correct_offset, begin_offset); + } + + if (len > 0) { + /* now move the marshalled buffer to the end of the main buffer */ + memmove(ndr->data + correct_offset, ndr->data + begin_offset, len); + + /* and wipe out old buffer within the main buffer */ + memset(ndr->data + begin_offset, '\0', len); + } + + /* and set the end offset for the next buffer */ + ndr->relative_end_offset = correct_offset; + + /* finally write the offset to the main buffer */ + ndr->offset = correct_offset; + NDR_CHECK(ndr_push_relative_ptr2(ndr, p)); + + /* restore to where we were in the main buffer */ + ndr->offset = begin_offset; + + return NDR_ERR_SUCCESS; +} /* get the current base for relative pointers for the pull @@ -1122,3 +1327,39 @@ _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const vo NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset)); return ndr_pull_set_offset(ndr, rel_offset); } + +const static struct { + enum ndr_err_code err; + const char *string; +} ndr_err_code_strings[] = { + { NDR_ERR_SUCCESS, "Success" }, + { NDR_ERR_ARRAY_SIZE, "Bad Array Size" }, + { NDR_ERR_BAD_SWITCH, "Bad Switch" }, + { NDR_ERR_OFFSET, "Offset Error" }, + { NDR_ERR_RELATIVE, "Relative Pointer Error" }, + { NDR_ERR_CHARCNV, "Character Conversion Error" }, + { NDR_ERR_LENGTH, "Length Error" }, + { NDR_ERR_SUBCONTEXT, "Subcontext Error" }, + { NDR_ERR_COMPRESSION, "Compression Error" }, + { NDR_ERR_STRING, "String Error" }, + { NDR_ERR_VALIDATE, "Validate Error" }, + { NDR_ERR_BUFSIZE, "Buffer Size Error" }, + { NDR_ERR_ALLOC, "Allocation Error" }, + { NDR_ERR_RANGE, "Range Error" }, + { NDR_ERR_TOKEN, "Token Error" }, + { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" }, + { NDR_ERR_INVALID_POINTER, "Invalid Pointer" }, + { NDR_ERR_UNREAD_BYTES, "Unread Bytes" }, + { NDR_ERR_NDR64, "NDR64 assertion error" }, + { 0, NULL } +}; + +_PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err) +{ + int i; + for (i = 0; ndr_err_code_strings[i].string != NULL; i++) { + if (ndr_err_code_strings[i].err == ndr_err) + return ndr_err_code_strings[i].string; + } + return "Unknown error"; +}