diff options
Diffstat (limited to 'source3/librpc/ndr')
-rw-r--r-- | source3/librpc/ndr/libndr.h | 354 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr.c | 1101 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_basic.c | 859 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_compression.c | 293 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_compression.h | 51 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_drsuapi.c | 177 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_drsuapi.h | 35 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_krb5pac.c | 141 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_misc.c | 94 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_sec.h | 35 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_sec_helper.c | 117 | ||||
-rw-r--r-- | source3/librpc/ndr/ndr_string.c | 738 | ||||
-rw-r--r-- | source3/librpc/ndr/sid.c | 230 | ||||
-rw-r--r-- | source3/librpc/ndr/uuid.c | 227 |
14 files changed, 4452 insertions, 0 deletions
diff --git a/source3/librpc/ndr/libndr.h b/source3/librpc/ndr/libndr.h new file mode 100644 index 0000000000..155f5f1f7d --- /dev/null +++ b/source3/librpc/ndr/libndr.h @@ -0,0 +1,354 @@ +/* + Unix SMB/CIFS implementation. + rpc interface definitions + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LIBNDR_H__ +#define __LIBNDR_H__ + +#define _PRINTF_ATTRIBUTE(a,b) + +#include "librpc/gen_ndr/misc.h" +#include "librpc/gen_ndr/security.h" + +/* + this provides definitions for the libcli/rpc/ MSRPC library +*/ + + +/* + this is used by the token store/retrieve code +*/ +struct ndr_token_list { + struct ndr_token_list *next, *prev; + const void *key; + uint32_t value; +}; + +/* this is the base structure passed to routines that + parse MSRPC formatted data + + note that in Samba4 we use separate routines and structures for + MSRPC marshalling and unmarshalling. Also note that these routines + are being kept deliberately very simple, and are not tied to a + particular transport +*/ +struct ndr_pull { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t data_size; + uint32_t offset; + + uint32_t relative_base_offset; + struct ndr_token_list *relative_base_list; + + struct ndr_token_list *relative_list; + struct ndr_token_list *array_size_list; + struct ndr_token_list *array_length_list; + struct ndr_token_list *switch_list; + + TALLOC_CTX *current_mem_ctx; + + /* this is used to ensure we generate unique reference IDs + between request and reply */ + uint32_t ptr_count; +}; + +struct ndr_pull_save { + uint32_t data_size; + uint32_t offset; + struct ndr_pull_save *next; +}; + +/* structure passed to functions that generate NDR formatted data */ +struct ndr_push { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t alloc_size; + uint32_t offset; + + uint32_t relative_base_offset; + struct ndr_token_list *relative_base_list; + + struct ndr_token_list *switch_list; + struct ndr_token_list *relative_list; + struct ndr_token_list *nbt_string_list; + struct ndr_token_list *full_ptr_list; + + /* this is used to ensure we generate unique reference IDs */ + uint32_t ptr_count; +}; + +struct ndr_push_save { + uint32_t offset; + struct ndr_push_save *next; +}; + + +/* structure passed to functions that print IDL structures */ +struct ndr_print { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint32_t depth; + struct ndr_token_list *switch_list; + void (*print)(struct ndr_print *, const char *, ...) PRINTF_ATTRIBUTE(2,3); + void *private_data; +}; + +#define LIBNDR_FLAG_BIGENDIAN (1<<0) +#define LIBNDR_FLAG_NOALIGN (1<<1) + +#define LIBNDR_FLAG_STR_ASCII (1<<2) +#define LIBNDR_FLAG_STR_LEN4 (1<<3) +#define LIBNDR_FLAG_STR_SIZE4 (1<<4) +#define LIBNDR_FLAG_STR_NOTERM (1<<5) +#define LIBNDR_FLAG_STR_NULLTERM (1<<6) +#define LIBNDR_FLAG_STR_SIZE2 (1<<7) +#define LIBNDR_FLAG_STR_BYTESIZE (1<<8) +#define LIBNDR_FLAG_STR_FIXLEN32 (1<<9) +#define LIBNDR_FLAG_STR_CONFORMANT (1<<10) +#define LIBNDR_FLAG_STR_CHARLEN (1<<11) +#define LIBNDR_FLAG_STR_UTF8 (1<<12) +#define LIBNDR_FLAG_STR_FIXLEN15 (1<<13) +#define LIBNDR_STRING_FLAGS (0x7FFC) + + +#define LIBNDR_FLAG_REF_ALLOC (1<<20) +#define LIBNDR_FLAG_REMAINING (1<<21) +#define LIBNDR_FLAG_ALIGN2 (1<<22) +#define LIBNDR_FLAG_ALIGN4 (1<<23) +#define LIBNDR_FLAG_ALIGN8 (1<<24) + +#define LIBNDR_ALIGN_FLAGS (LIBNDR_FLAG_ALIGN2|LIBNDR_FLAG_ALIGN4|LIBNDR_FLAG_ALIGN8) + +#define LIBNDR_PRINT_ARRAY_HEX (1<<25) +#define LIBNDR_PRINT_SET_VALUES (1<<26) + +/* used to force a section of IDL to be little-endian */ +#define LIBNDR_FLAG_LITTLE_ENDIAN (1<<27) + +/* used to check if alignment padding is zero */ +#define LIBNDR_FLAG_PAD_CHECK (1<<28) + +/* set if an object uuid will be present */ +#define LIBNDR_FLAG_OBJECT_PRESENT (1<<30) + +/* set to avoid recursion in ndr_size_*() calculation */ +#define LIBNDR_FLAG_NO_NDR_SIZE (1<<31) + +/* useful macro for debugging with DEBUG */ +#define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p) +#define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_fn_t)ndr_print_ ##type, #p, level, p) +#define NDR_PRINT_FUNCTION_DEBUG(type, flags, p) ndr_print_function_debug((ndr_print_function_t)ndr_print_ ##type, #type, flags, p) +#define NDR_PRINT_BOTH_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_BOTH, p) +#define NDR_PRINT_OUT_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_OUT, p) +#define NDR_PRINT_IN_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_IN | NDR_SET_VALUES, p) + +/* useful macro for debugging in strings */ +#define NDR_PRINT_STRUCT_STRING(ctx, type, p) ndr_print_struct_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, p) +#define NDR_PRINT_UNION_STRING(ctx, type, level, p) ndr_print_union_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, level, p) +#define NDR_PRINT_FUNCTION_STRING(ctx, type, flags, p) ndr_print_function_string(ctx, (ndr_print_function_t)ndr_print_ ##type, #type, flags, p) +#define NDR_PRINT_BOTH_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_BOTH, p) +#define NDR_PRINT_OUT_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_OUT, p) +#define NDR_PRINT_IN_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_IN | NDR_SET_VALUES, p) + +#define NDR_BE(ndr) (((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN) + +enum ndr_err_code { + NDR_ERR_SUCCESS = 0, + NDR_ERR_ARRAY_SIZE, + NDR_ERR_BAD_SWITCH, + NDR_ERR_OFFSET, + NDR_ERR_RELATIVE, + NDR_ERR_CHARCNV, + NDR_ERR_LENGTH, + NDR_ERR_SUBCONTEXT, + NDR_ERR_COMPRESSION, + NDR_ERR_STRING, + NDR_ERR_VALIDATE, + NDR_ERR_BUFSIZE, + NDR_ERR_ALLOC, + NDR_ERR_RANGE, + NDR_ERR_TOKEN, + NDR_ERR_IPV4ADDRESS, + NDR_ERR_INVALID_POINTER, + NDR_ERR_UNREAD_BYTES +}; + +#define NDR_ERR_CODE_IS_SUCCESS(x) (x == NDR_ERR_SUCCESS) + +#define NDR_ERR_HAVE_NO_MEMORY(x) do { \ + if (NULL == (x)) { \ + return NDR_ERR_ALLOC; \ + } \ +} while (0) + +enum ndr_compression_alg { + NDR_COMPRESSION_MSZIP = 2, + NDR_COMPRESSION_XPRESS = 3 +}; + +/* + flags passed to control parse flow +*/ +#define NDR_SCALARS 1 +#define NDR_BUFFERS 2 + +/* + flags passed to ndr_print_*() +*/ +#define NDR_IN 1 +#define NDR_OUT 2 +#define NDR_BOTH 3 +#define NDR_SET_VALUES 4 + +#define NDR_PULL_NEED_BYTES(ndr, n) do { \ + if ((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size) { \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %u", (unsigned)n); \ + } \ +} while(0) + +#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n) + +#define NDR_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1)) + +#define NDR_PULL_ALIGN(ndr, n) do { \ + if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ + if (ndr->flags & LIBNDR_FLAG_PAD_CHECK) { \ + ndr_check_padding(ndr, n); \ + } \ + ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ + } \ + if (ndr->offset > ndr->data_size) { \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %u", (unsigned)n); \ + } \ +} while(0) + +#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, n)) + +#define NDR_PUSH_ALIGN(ndr, n) do { \ + if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ + uint32_t _pad = ((ndr->offset + (n-1)) & ~(n-1)) - ndr->offset; \ + while (_pad--) NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0)); \ + } \ +} while(0) + +/* these are used to make the error checking on each element in libndr + less tedious, hopefully making the code more readable */ +#define NDR_CHECK(call) do { \ + enum ndr_err_code _status; \ + _status = call; \ + if (!NDR_ERR_CODE_IS_SUCCESS(_status)) { \ + return _status; \ + } \ +} while (0) + +#define NDR_PULL_GET_MEM_CTX(ndr) (ndr->current_mem_ctx) + +#define NDR_PULL_SET_MEM_CTX(ndr, mem_ctx, flgs) do {\ + if ( !(flgs) || (ndr->flags & flgs) ) {\ + if (!(mem_ctx)) {\ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "NDR_PULL_SET_MEM_CTX(NULL): %s\n", __location__); \ + }\ + ndr->current_mem_ctx = discard_const(mem_ctx);\ + }\ +} while(0) + +#define _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr) do {\ + if (!ndr->current_mem_ctx) {\ + ndr->current_mem_ctx = talloc_new(ndr);\ + if (!ndr->current_mem_ctx) {\ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "_NDR_PULL_FIX_CURRENT_MEM_CTX() failed: %s\n", __location__); \ + }\ + }\ +} while(0) + +#define NDR_PULL_ALLOC(ndr, s) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_ptrtype(ndr->current_mem_ctx, (s)); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %s failed: %s\n", # s, __location__); \ +} while (0) + +#define NDR_PULL_ALLOC_N(ndr, s, n) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_array_ptrtype(ndr->current_mem_ctx, (s), n); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u * %s failed: %s\n", (unsigned)n, # s, __location__); \ +} while (0) + + +#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \ + (s) = talloc_array(ndr, uint8_t, size); \ + if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %u failed: %s\n", (unsigned)size, __location__); \ +} while (0) + +#define NDR_PUSH_ALLOC(ndr, s) do { \ + (s) = talloc_ptrtype(ndr, (s)); \ + if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %s failed: %s\n", # s, __location__); \ +} while (0) + +/* these are used when generic fn pointers are needed for ndr push/pull fns */ +typedef enum ndr_err_code (*ndr_push_flags_fn_t)(struct ndr_push *, int ndr_flags, const void *); +typedef enum ndr_err_code (*ndr_pull_flags_fn_t)(struct ndr_pull *, int ndr_flags, void *); +typedef void (*ndr_print_fn_t)(struct ndr_print *, const char *, const void *); +typedef void (*ndr_print_function_t)(struct ndr_print *, const char *, int, const void *); + +extern const struct ndr_syntax_id ndr_transfer_syntax; +extern const struct ndr_syntax_id ndr64_transfer_syntax; + +struct ndr_interface_call { + const char *name; + size_t struct_size; + ndr_push_flags_fn_t ndr_push; + ndr_pull_flags_fn_t ndr_pull; + ndr_print_function_t ndr_print; + bool async; +}; + +struct ndr_interface_string_array { + uint32_t count; + const char * const *names; +}; + +struct ndr_interface_table { + const char *name; + struct ndr_syntax_id syntax_id; + const char *helpstring; + uint32_t num_calls; + const struct ndr_interface_call *calls; + const struct ndr_interface_string_array *endpoints; + const struct ndr_interface_string_array *authservices; +}; + +struct ndr_interface_list { + struct ndr_interface_list *prev, *next; + const struct ndr_interface_table *table; +}; + +#define NDR_SCALAR_PROTO(name, type) \ +enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, int ndr_flags, type v); \ +enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, int ndr_flags, type *v); \ +void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, type v); + +#define NDR_BUFFER_PROTO(name, type) \ +enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, int ndr_flags, const type *v); \ +enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, int ndr_flags, type *v); \ +void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v); + + +void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags); + +#endif /* __LIBNDR_H__ */ diff --git a/source3/librpc/ndr/ndr.c b/source3/librpc/ndr/ndr.c new file mode 100644 index 0000000000..d94d12e146 --- /dev/null +++ b/source3/librpc/ndr/ndr.c @@ -0,0 +1,1101 @@ +/* + Unix SMB/CIFS implementation. + + libndr interface + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + this provides the core routines for NDR parsing functions + + see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details + of NDR encoding rules +*/ + +#include "includes.h" + +#define NDR_BASE_MARSHALL_SIZE 1024 + +/* this guid indicates NDR encoding in a protocol tower */ +const struct ndr_syntax_id ndr_transfer_syntax = { + { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} }, + 2 +}; + +const struct ndr_syntax_id ndr64_transfer_syntax = { + { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} }, + 1 +}; + +/* + work out the number of bytes needed to align on a n byte boundary +*/ +_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n) +{ + if ((offset & (n-1)) == 0) return 0; + return n - (offset & (n-1)); +} + +/* + initialise a ndr parse structure from a data blob +*/ +_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx) +{ + struct ndr_pull *ndr; + + ndr = talloc_zero(mem_ctx, struct ndr_pull); + if (!ndr) return NULL; + ndr->current_mem_ctx = mem_ctx; + + ndr->data = blob->data; + ndr->data_size = blob->length; + + return ndr; +} + +/* + advance by 'size' bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size) +{ + ndr->offset += size; + if (ndr->offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_advance by %u failed", + size); + } + return NDR_ERR_SUCCESS; +} + +/* + set the parse offset to 'ofs' +*/ +static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs) +{ + ndr->offset = ofs; + if (ndr->offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_set_offset %u failed", + ofs); + } + return NDR_ERR_SUCCESS; +} + +/* save the offset/size of the current ndr state */ +_PUBLIC_ void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save) +{ + save->offset = ndr->offset; + save->data_size = ndr->data_size; +} + +/* restore the size/offset of a ndr structure */ +_PUBLIC_ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save) +{ + ndr->offset = save->offset; + ndr->data_size = save->data_size; +} + + +/* create a ndr_push structure, ready for some marshalling */ +_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx) +{ + struct ndr_push *ndr; + + ndr = talloc_zero(mem_ctx, struct ndr_push); + if (!ndr) { + return NULL; + } + + ndr->flags = 0; + ndr->alloc_size = NDR_BASE_MARSHALL_SIZE; + ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size); + if (!ndr->data) { + return NULL; + } + + return ndr; +} + +/* return a DATA_BLOB structure for the current ndr_push marshalled data */ +_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr) +{ + DATA_BLOB blob; + blob = data_blob_const(ndr->data, ndr->offset); + if (ndr->alloc_size > ndr->offset) { + ndr->data[ndr->offset] = 0; + } + return blob; +} + + +/* + expand the available space in the buffer to ndr->offset + extra_size +*/ +_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size) +{ + uint32_t size = extra_size + ndr->offset; + + if (size < ndr->offset) { + /* extra_size overflowed the offset */ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u", + size); + } + + if (ndr->alloc_size > size) { + return NDR_ERR_SUCCESS; + } + + ndr->alloc_size += NDR_BASE_MARSHALL_SIZE; + if (size+1 > ndr->alloc_size) { + ndr->alloc_size = size+1; + } + ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size); + if (!ndr->data) { + return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u", + ndr->alloc_size); + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3) +{ + va_list ap; + char *s = NULL; + int i, ret; + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return; + } + + for (i=0;i<ndr->depth;i++) { + DEBUGADD(0,(" ")); + } + + DEBUGADD(0,("%s\n", s)); + free(s); +} + +_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3) +{ + va_list ap; + int i; + + for (i=0;i<ndr->depth;i++) { + ndr->private_data = talloc_asprintf_append_buffer( + (char *)ndr->private_data, " "); + } + + va_start(ap, format); + ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data, + format, ap); + va_end(ap); + ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data, + "\n"); +} + +/* + a useful helper function for printing idl structures via DEBUG() +*/ +_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl unions via DEBUG() +*/ +_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + ndr_print_set_switch_value(ndr, ptr, level); + fn(ndr, name, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl function calls via DEBUG() +*/ +_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, flags, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl structures to a string +*/ +_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr) +{ + struct ndr_print *ndr; + char *ret = NULL; + + ndr = talloc_zero(mem_ctx, struct ndr_print); + if (!ndr) return NULL; + ndr->private_data = talloc_strdup(ndr, ""); + if (!ndr->private_data) { + goto failed; + } + ndr->print = ndr_print_string_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, ptr); + ret = talloc_steal(mem_ctx, (char *)ndr->private_data); +failed: + talloc_free(ndr); + return ret; +} + +/* + a useful helper function for printing idl unions to a string +*/ +_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr) +{ + struct ndr_print *ndr; + char *ret = NULL; + + ndr = talloc_zero(mem_ctx, struct ndr_print); + if (!ndr) return NULL; + ndr->private_data = talloc_strdup(ndr, ""); + if (!ndr->private_data) { + goto failed; + } + ndr->print = ndr_print_string_helper; + ndr->depth = 1; + ndr->flags = 0; + ndr_print_set_switch_value(ndr, ptr, level); + fn(ndr, name, ptr); + ret = talloc_steal(mem_ctx, (char *)ndr->private_data); +failed: + talloc_free(ndr); + return ret; +} + +/* + a useful helper function for printing idl function calls to a string +*/ +_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx, + ndr_print_function_t fn, const char *name, + int flags, void *ptr) +{ + struct ndr_print *ndr; + char *ret = NULL; + + ndr = talloc_zero(mem_ctx, struct ndr_print); + if (!ndr) return NULL; + ndr->private_data = talloc_strdup(ndr, ""); + if (!ndr->private_data) { + goto failed; + } + ndr->print = ndr_print_string_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, flags, ptr); + ret = talloc_steal(mem_ctx, (char *)ndr->private_data); +failed: + talloc_free(ndr); + return ret; +} + +_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; + } + if (new_flags & LIBNDR_FLAG_BIGENDIAN) { + (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN; + } + if (new_flags & LIBNDR_FLAG_REMAINING) { + (*pflags) &= ~LIBNDR_ALIGN_FLAGS; + } + if (new_flags & LIBNDR_ALIGN_FLAGS) { + (*pflags) &= ~LIBNDR_FLAG_REMAINING; + } + (*pflags) |= new_flags; +} + +NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err) +{ + switch (ndr_err) { + case NDR_ERR_SUCCESS: + return NT_STATUS_OK; + case NDR_ERR_BUFSIZE: + return NT_STATUS_BUFFER_TOO_SMALL; + case NDR_ERR_TOKEN: + return NT_STATUS_INTERNAL_ERROR; + case NDR_ERR_ALLOC: + return NT_STATUS_NO_MEMORY; + case NDR_ERR_ARRAY_SIZE: + return NT_STATUS_ARRAY_BOUNDS_EXCEEDED; + case NDR_ERR_INVALID_POINTER: + return NT_STATUS_INVALID_PARAMETER_MIX; + case NDR_ERR_UNREAD_BYTES: + return NT_STATUS_PORT_MESSAGE_TOO_LONG; + default: + break; + } + + /* we should map all error codes to different status codes */ + return NT_STATUS_INVALID_PARAMETER; +} + +/* + * Convert an ndr error to string + */ + +const char *ndr_errstr(enum ndr_err_code err) +{ + switch (err) { + case NDR_ERR_SUCCESS: + return "NDR_ERR_SUCCESS"; + break; + case NDR_ERR_ARRAY_SIZE: + return "NDR_ERR_ARRAY_SIZE"; + break; + case NDR_ERR_BAD_SWITCH: + return "NDR_ERR_BAD_SWITCH"; + break; + case NDR_ERR_OFFSET: + return "NDR_ERR_OFFSET"; + break; + case NDR_ERR_RELATIVE: + return "NDR_ERR_RELATIVE"; + break; + case NDR_ERR_CHARCNV: + return "NDR_ERR_CHARCNV"; + break; + case NDR_ERR_LENGTH: + return "NDR_ERR_LENGTH"; + break; + case NDR_ERR_SUBCONTEXT: + return "NDR_ERR_SUBCONTEXT"; + break; + case NDR_ERR_COMPRESSION: + return "NDR_ERR_COMPRESSION"; + break; + case NDR_ERR_STRING: + return "NDR_ERR_STRING"; + break; + case NDR_ERR_VALIDATE: + return "NDR_ERR_VALIDATE"; + break; + case NDR_ERR_BUFSIZE: + return "NDR_ERR_BUFSIZE"; + break; + case NDR_ERR_ALLOC: + return "NDR_ERR_ALLOC"; + break; + case NDR_ERR_RANGE: + return "NDR_ERR_RANGE"; + break; + case NDR_ERR_TOKEN: + return "NDR_ERR_TOKEN"; + break; + case NDR_ERR_IPV4ADDRESS: + return "NDR_ERR_IPV4ADDRESS"; + break; + case NDR_ERR_INVALID_POINTER: + return "NDR_ERR_INVALID_POINTER"; + break; + case NDR_ERR_UNREAD_BYTES: + return "NDR_ERR_UNREAD_BYTES"; + break; + } + + return talloc_asprintf(talloc_tos(), "Unknown NDR error: %d", err); +} + +/* + return and possibly log an NDR error +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr, + enum ndr_err_code ndr_err, + const char *format, ...) _PRINTF_ATTRIBUTE(3,4) +{ + char *s=NULL; + va_list ap; + int ret; + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return NDR_ERR_ALLOC; + } + + DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s)); + + free(s); + + return ndr_err; +} + +/* + return and possibly log an NDR error +*/ +_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr, + enum ndr_err_code ndr_err, + const char *format, ...) _PRINTF_ATTRIBUTE(3,4) +{ + char *s=NULL; + va_list ap; + int ret; + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return NDR_ERR_ALLOC; + } + + DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s)); + + free(s); + + return ndr_err; +} + +/* + 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; + + 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_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); + } + r_content_size = content_size; + 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; + subndr->current_mem_ctx = ndr->current_mem_ctx; + + subndr->data = ndr->data + ndr->offset; + subndr->offset = 0; + subndr->data_size = r_content_size; + + *_subndr = subndr; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr, + struct ndr_pull *subndr, + size_t header_size, + ssize_t size_is) +{ + uint32_t advance; + if (size_is >= 0) { + advance = size_is; + } else if (header_size > 0) { + advance = subndr->data_size; + } else { + advance = subndr->offset; + } + NDR_CHECK(ndr_pull_advance(ndr, advance)); + return NDR_ERR_SUCCESS; +} + +_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_ERR_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags; + + *_subndr = subndr; + return NDR_ERR_SUCCESS; +} + +/* + push a subcontext header +*/ +_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr, + struct ndr_push *subndr, + size_t header_size, + ssize_t size_is) +{ + if (size_is >= 0) { + ssize_t padding_len = size_is - subndr->offset; + if (padding_len > 0) { + NDR_CHECK(ndr_push_zero(subndr, padding_len)); + } else 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); + } + } + + switch (header_size) { + case 0: + break; + + case 2: + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset)); + break; + + case 4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset)); + break; + + default: + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d", + (int)header_size); + } + + NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset)); + 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; +} + +/* + retrieve a token from a ndr context, using cmp_fn to match the tokens +*/ +_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v, + comparison_fn_t _cmp_fn, bool _remove_tok) +{ + struct ndr_token_list *tok; + for (tok=*list;tok;tok=tok->next) { + if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found; + else if (!_cmp_fn && tok->key == key) goto found; + } + return NDR_ERR_TOKEN; +found: + *v = tok->value; + if (_remove_tok) { + DLIST_REMOVE((*list), tok); + talloc_free(tok); + } + return NDR_ERR_SUCCESS; +} + +/* + retrieve a token from a ndr context +*/ +_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v) +{ + return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true); +} + +/* + peek at but don't removed a token from a ndr context +*/ +_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key) +{ + enum ndr_err_code status; + uint32_t v; + + status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + return 0; + } + + return v; +} + +/* + 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_uint32(ndr, NDR_SCALARS, &size)); + return ndr_token_store(ndr, &ndr->array_size_list, p, size); +} + +/* + get the stored array size field +*/ +_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->array_size_list, p); +} + +/* + check the stored array size field +*/ +_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size) +{ + uint32_t stored; + stored = ndr_token_peek(&ndr->array_size_list, p); + if (stored != size) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array size - got %u expected %u\n", + stored, size); + } + return NDR_ERR_SUCCESS; +} + +/* + 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_uint32(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)); + return ndr_token_store(ndr, &ndr->array_length_list, p, length); +} + +/* + get the stored array length field +*/ +_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->array_length_list, p); +} + +/* + check the stored array length field +*/ +_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length) +{ + uint32_t stored; + stored = ndr_token_peek(&ndr->array_length_list, p); + if (stored != length) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array length - got %u expected %u\n", + stored, length); + } + return NDR_ERR_SUCCESS; +} + +/* + store a switch value + */ +_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val) +{ + return ndr_token_store(ndr, &ndr->switch_list, p, val); +} + +_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val) +{ + return ndr_token_store(ndr, &ndr->switch_list, p, val); +} + +_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val) +{ + return ndr_token_store(ndr, &ndr->switch_list, p, val); +} + +/* + retrieve a switch value + */ +_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +/* + 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, void *p, + 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(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + return NDR_ERR_SUCCESS; +} + +/* + 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, void *p, + 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(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); + } + 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(ndr_pull_set_switch_value(ndr, p, level)); + NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + 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; + ndr = ndr_pull_init_blob(blob, mem_ctx); + 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); + } + 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, 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_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; +} + +/* + 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; +} + +/* + generic ndr_size_*() handler for structures +*/ +_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push) +{ + struct ndr_push *ndr; + enum ndr_err_code status; + size_t ret; + + /* avoid recursion */ + if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0; + + ndr = ndr_push_init_ctx(NULL); + if (!ndr) return 0; + ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE; + status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p)); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + talloc_free(ndr); + return 0; + } + ret = ndr->offset; + talloc_free(ndr); + return ret; +} + +/* + generic ndr_size_*() handler for unions +*/ +_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push) +{ + struct ndr_push *ndr; + enum ndr_err_code status; + size_t ret; + + /* avoid recursion */ + if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0; + + ndr = ndr_push_init_ctx(NULL); + if (!ndr) return 0; + ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE; + + status = ndr_push_set_switch_value(ndr, p, level); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + talloc_free(ndr); + return 0; + } + status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + talloc_free(ndr); + return 0; + } + ret = ndr->offset; + talloc_free(ndr); + return ret; +} + +/* + get the current base for relative pointers for the push +*/ +_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr) +{ + return ndr->relative_base_offset; +} + +/* + restore the old base for relative pointers for the push +*/ +_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset) +{ + ndr->relative_base_offset = offset; +} + +/* + setup the current base for relative pointers for the push + called in the NDR_SCALAR stage +*/ +_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset) +{ + ndr->relative_base_offset = offset; + return ndr_token_store(ndr, &ndr->relative_base_list, p, offset); +} + +/* + setup the current base for relative pointers for the push + called in the NDR_BUFFERS stage +*/ +_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p) +{ + return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset); +} + +/* + push a relative object - stage1 + this is called during SCALARS processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p) +{ + if (p == NULL) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset)); + return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF); +} + +/* + 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) +{ + struct ndr_push_save save; + uint32_t ptr_offset = 0xFFFFFFFF; + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + ndr_push_save(ndr, &save); + 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_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_uint32(ndr, NDR_SCALARS, save.offset - ndr->relative_base_offset)); + ndr_push_restore(ndr, &save); + return NDR_ERR_SUCCESS; +} + +/* + get the current base for relative pointers for the pull +*/ +_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr) +{ + return ndr->relative_base_offset; +} + +/* + restore the old base for relative pointers for the pull +*/ +_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset) +{ + ndr->relative_base_offset = offset; +} + +/* + setup the current base for relative pointers for the pull + called in the NDR_SCALAR stage +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset) +{ + ndr->relative_base_offset = offset; + return ndr_token_store(ndr, &ndr->relative_base_list, p, offset); +} + +/* + setup the current base for relative pointers for the pull + called in the NDR_BUFFERS stage +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset); +} + +/* + pull a relative object - stage1 + called during SCALARS processing +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset) +{ + rel_offset += ndr->relative_base_offset; + if (rel_offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)", + rel_offset, ndr->data_size); + } + return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset); +} + +/* + pull a relative object - stage2 + called during BUFFERS processing +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p) +{ + uint32_t rel_offset; + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset)); + return ndr_pull_set_offset(ndr, rel_offset); +} diff --git a/source3/librpc/ndr/ndr_basic.c b/source3/librpc/ndr/ndr_basic.c new file mode 100644 index 0000000000..c8fa70b185 --- /dev/null +++ b/source3/librpc/ndr/ndr_basic.c @@ -0,0 +1,859 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling basic types + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/network.h" +#include "librpc/ndr/libndr.h" + +#define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs)) +#define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs)) +#define NDR_IVALS(ndr, ofs) (NDR_BE(ndr)?RIVALS(ndr->data,ofs):IVALS(ndr->data,ofs)) +#define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0) +#define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0) +#define NDR_SIVALS(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVALS(ndr->data,ofs,v); } else SIVALS(ndr->data,ofs,v); } while (0) + + +/* + check for data leaks from the server by looking for non-zero pad bytes + these could also indicate that real structure elements have been + mistaken for padding in the IDL +*/ +_PUBLIC_ void ndr_check_padding(struct ndr_pull *ndr, size_t n) +{ + size_t ofs2 = (ndr->offset + (n-1)) & ~(n-1); + int i; + for (i=ndr->offset;i<ofs2;i++) { + if (ndr->data[i] != 0) { + break; + } + } + if (i<ofs2) { + DEBUG(0,("WARNING: Non-zero padding to %d: ", (int)n)); + for (i=ndr->offset;i<ofs2;i++) { + DEBUG(0,("%02x ", ndr->data[i])); + } + DEBUG(0,("\n")); + } + +} + +/* + parse a int8_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, int ndr_flags, int8_t *v) +{ + NDR_PULL_NEED_BYTES(ndr, 1); + *v = (int8_t)CVAL(ndr->data, ndr->offset); + ndr->offset += 1; + return NDR_ERR_SUCCESS; +} + +/* + parse a uint8_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *v) +{ + NDR_PULL_NEED_BYTES(ndr, 1); + *v = CVAL(ndr->data, ndr->offset); + ndr->offset += 1; + return NDR_ERR_SUCCESS; +} + +/* + parse a int16_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int16(struct ndr_pull *ndr, int ndr_flags, int16_t *v) +{ + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = (uint16_t)NDR_SVAL(ndr, ndr->offset); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + parse a uint16_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *v) +{ + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = NDR_SVAL(ndr, ndr->offset); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + parse a int32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, int ndr_flags, int32_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_IVALS(ndr, ndr->offset); + ndr->offset += 4; + return NDR_ERR_SUCCESS; +} + +/* + parse a uint32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_IVAL(ndr, ndr->offset); + ndr->offset += 4; + 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_uint32(ndr, NDR_SCALARS, v)); + if (*v != 0) { + ndr->ptr_count++; + } + return NDR_ERR_SUCCESS; +} + +/* + 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_uint32(ndr, NDR_SCALARS, v)); + /* ref pointers always point to data */ + *v = 1; + return NDR_ERR_SUCCESS; +} + +/* + parse a udlong +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = NDR_IVAL(ndr, ndr->offset); + *v |= (uint64_t)(NDR_IVAL(ndr, ndr->offset+4)) << 32; + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + parse a udlongr +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = ((uint64_t)NDR_IVAL(ndr, ndr->offset)) << 32; + *v |= NDR_IVAL(ndr, ndr->offset+4); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + parse a dlong +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_dlong(struct ndr_pull *ndr, int ndr_flags, int64_t *v) +{ + return ndr_pull_udlong(ndr, ndr_flags, (uint64_t *)v); +} + +/* + parse a hyper +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_hyper(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 8); + return ndr_pull_udlong(ndr, ndr_flags, v); +} + +/* + parse a pointer +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, int ndr_flags, void* *v) +{ + uintptr_t h; + NDR_PULL_ALIGN(ndr, sizeof(h)); + NDR_PULL_NEED_BYTES(ndr, sizeof(h)); + memcpy(&h, ndr->data+ndr->offset, sizeof(h)); + ndr->offset += sizeof(h); + *v = (void *)h; + return NDR_ERR_SUCCESS; +} + +/* + pull a NTSTATUS +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_NTSTATUS(struct ndr_pull *ndr, int ndr_flags, NTSTATUS *status) +{ + uint32_t v; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = NT_STATUS(v); + return NDR_ERR_SUCCESS; +} + +/* + push a NTSTATUS +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTSTATUS(struct ndr_push *ndr, int ndr_flags, NTSTATUS status) +{ + return ndr_push_uint32(ndr, ndr_flags, NT_STATUS_V(status)); +} + +_PUBLIC_ void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS r) +{ + ndr->print(ndr, "%-25s: %s", name, nt_errstr(r)); +} + +/* + pull a WERROR +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_WERROR(struct ndr_pull *ndr, int ndr_flags, WERROR *status) +{ + uint32_t v; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = W_ERROR(v); + return NDR_ERR_SUCCESS; +} + +/* + push a WERROR +*/ +_PUBLIC_ enum ndr_err_code ndr_push_WERROR(struct ndr_push *ndr, int ndr_flags, WERROR status) +{ + return ndr_push_uint32(ndr, NDR_SCALARS, W_ERROR_V(status)); +} + +_PUBLIC_ void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR r) +{ + ndr->print(ndr, "%-25s: %s", name, win_errstr(r)); +} + +/* + parse a set of bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n) +{ + NDR_PULL_NEED_BYTES(ndr, n); + memcpy(data, ndr->data + ndr->offset, n); + ndr->offset += n; + return NDR_ERR_SUCCESS; +} + +/* + pull an array of uint8 +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *data, uint32_t n) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + return ndr_pull_bytes(ndr, data, n); +} + +/* + push a int8_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_int8(struct ndr_push *ndr, int ndr_flags, int8_t v) +{ + NDR_PUSH_NEED_BYTES(ndr, 1); + SCVAL(ndr->data, ndr->offset, (uint8_t)v); + ndr->offset += 1; + return NDR_ERR_SUCCESS; +} + +/* + push a uint8_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uint8(struct ndr_push *ndr, int ndr_flags, uint8_t v) +{ + NDR_PUSH_NEED_BYTES(ndr, 1); + SCVAL(ndr->data, ndr->offset, v); + ndr->offset += 1; + return NDR_ERR_SUCCESS; +} + +/* + push a int16_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_int16(struct ndr_push *ndr, int ndr_flags, int16_t v) +{ + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_SSVAL(ndr, ndr->offset, (uint16_t)v); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + push a uint16_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uint16(struct ndr_push *ndr, int ndr_flags, uint16_t v) +{ + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_SSVAL(ndr, ndr->offset, v); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + push a int32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_SIVALS(ndr, ndr->offset, v); + ndr->offset += 4; + return NDR_ERR_SUCCESS; +} + +/* + push a uint32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uint32(struct ndr_push *ndr, int ndr_flags, uint32_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_SIVAL(ndr, ndr->offset, v); + ndr->offset += 4; + return NDR_ERR_SUCCESS; +} + +/* + push a udlong +*/ +_PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF)); + NDR_SIVAL(ndr, ndr->offset+4, (v>>32)); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + push a udlongr +*/ +_PUBLIC_ enum ndr_err_code ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_SIVAL(ndr, ndr->offset, (v>>32)); + NDR_SIVAL(ndr, ndr->offset+4, (v & 0xFFFFFFFF)); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + push a dlong +*/ +_PUBLIC_ enum ndr_err_code ndr_push_dlong(struct ndr_push *ndr, int ndr_flags, int64_t v) +{ + return ndr_push_udlong(ndr, NDR_SCALARS, (uint64_t)v); +} + +/* + push a hyper +*/ +_PUBLIC_ enum ndr_err_code ndr_push_hyper(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 8); + return ndr_push_udlong(ndr, NDR_SCALARS, v); +} + +/* + push a pointer +*/ +_PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, int ndr_flags, void* v) +{ + uintptr_t h = (intptr_t)v; + NDR_PUSH_ALIGN(ndr, sizeof(h)); + NDR_PUSH_NEED_BYTES(ndr, sizeof(h)); + memcpy(ndr->data+ndr->offset, &h, sizeof(h)); + ndr->offset += sizeof(h); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size) +{ + NDR_PUSH_ALIGN(ndr, size); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size) +{ + NDR_PULL_ALIGN(ndr, size); + return NDR_ERR_SUCCESS; +} + +/* + push some bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n) +{ + NDR_PUSH_NEED_BYTES(ndr, n); + memcpy(ndr->data + ndr->offset, data, n); + ndr->offset += n; + return NDR_ERR_SUCCESS; +} + +/* + push some zero bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n) +{ + NDR_PUSH_NEED_BYTES(ndr, n); + memset(ndr->data + ndr->offset, 0, n); + ndr->offset += n; + return NDR_ERR_SUCCESS; +} + +/* + push an array of uint8 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const uint8_t *data, uint32_t n) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + return ndr_push_bytes(ndr, data, n); +} + +/* + save the current position + */ +_PUBLIC_ void ndr_push_save(struct ndr_push *ndr, struct ndr_push_save *save) +{ + save->offset = ndr->offset; +} + +/* + restore the position + */ +_PUBLIC_ void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save) +{ + ndr->offset = save->offset; +} + +/* + push a unique non-zero value if a pointer is non-NULL, otherwise 0 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p) +{ + uint32_t ptr = 0; + if (p) { + ptr = ndr->ptr_count * 4; + ptr |= 0x00020000; + ndr->ptr_count++; + } + return ndr_push_uint32(ndr, NDR_SCALARS, ptr); +} + +/* + push a 'simple' full non-zero value if a pointer is non-NULL, otherwise 0 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p) +{ + uint32_t ptr = 0; + if (p) { + /* Check if the pointer already exists and has an id */ + ptr = ndr_token_peek(&ndr->full_ptr_list, p); + if (ptr == 0) { + ndr->ptr_count++; + ptr = ndr->ptr_count; + ndr_token_store(ndr, &ndr->full_ptr_list, p, ptr); + } + } + return ndr_push_uint32(ndr, NDR_SCALARS, ptr); +} + +/* + push always a 0, if a pointer is NULL it's a fatal error +*/ +_PUBLIC_ enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr) +{ + return ndr_push_uint32(ndr, NDR_SCALARS, 0xAEF1AEF1); +} + + +/* + push a NTTIME +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + NDR_CHECK(ndr_push_udlong(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + pull a NTTIME +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + push a NTTIME +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + t /= 10000000; + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + pull a NTTIME_1sec +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t)); + (*t) *= 10000000; + return NDR_ERR_SUCCESS; +} + +/* + pull a NTTIME_hyper +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + push a NTTIME_hyper +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_hyper(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + push a time_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_time_t(struct ndr_push *ndr, int ndr_flags, time_t t) +{ + return ndr_push_uint32(ndr, ndr_flags, t); +} + +/* + pull a time_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_time_t(struct ndr_pull *ndr, int ndr_flags, time_t *t) +{ + uint32_t tt; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &tt)); + *t = tt; + 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; +} + +/* + push a ipv4address +*/ +_PUBLIC_ enum ndr_err_code ndr_push_ipv4address(struct ndr_push *ndr, int ndr_flags, const char *address) +{ + uint32_t addr; + if (!is_ipaddress(address)) { + return ndr_push_error(ndr, NDR_ERR_IPV4ADDRESS, + "Invalid IPv4 address: '%s'", + address); + } + addr = inet_addr(address); + NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, htonl(addr))); + return NDR_ERR_SUCCESS; +} + +/* + print a ipv4address +*/ +_PUBLIC_ void ndr_print_ipv4address(struct ndr_print *ndr, const char *name, + const char *address) +{ + ndr->print(ndr, "%-25s: %s", name, address); +} + + +_PUBLIC_ void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type) +{ + ndr->print(ndr, "%s: struct %s", name, type); +} + +_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type, + const char *val, uint32_t value) +{ + if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) { + ndr->print(ndr, "%-25s: %s (0x%X)", name, val?val:"UNKNOWN_ENUM_VALUE", value); + } else { + ndr->print(ndr, "%-25s: %s (%d)", name, val?val:"UNKNOWN_ENUM_VALUE", value); + } +} + +_PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value) +{ + /* this is an attempt to support multi-bit bitmap masks */ + value &= flag; + + while (!(flag & 1)) { + flag >>= 1; + value >>= 1; + } + if (flag == 1) { + ndr->print(ndr, " %d: %-25s", value, flag_name); + } else { + ndr->print(ndr, "0x%02x: %-25s (%d)", value, flag_name, value); + } +} + +_PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +_PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v) +{ + ndr->print(ndr, "%-25s: 0x%02x (%u)", name, v, v); +} + +_PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +_PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v) +{ + ndr->print(ndr, "%-25s: 0x%04x (%u)", name, v, v); +} + +_PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +_PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v) +{ + ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v); +} + +_PUBLIC_ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr->print(ndr, "%-25s: 0x%016llx (%llu)", name, (unsigned long long)v, (unsigned long long)v); +} + +_PUBLIC_ void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr_print_udlong(ndr, name, v); +} + +_PUBLIC_ void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v) +{ + ndr->print(ndr, "%-25s: 0x%016llx (%lld)", name, (unsigned long long)v, (long long)v); +} + +_PUBLIC_ void ndr_print_hyper(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr_print_dlong(ndr, name, v); +} + +_PUBLIC_ void ndr_print_pointer(struct ndr_print *ndr, const char *name, void *v) +{ + ndr->print(ndr, "%-25s: %p", name, v); +} + +_PUBLIC_ void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p) +{ + if (p) { + ndr->print(ndr, "%-25s: *", name); + } else { + ndr->print(ndr, "%-25s: NULL", name); + } +} + +_PUBLIC_ void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t) +{ + ndr->print(ndr, "%-25s: %s", name, nt_time_string(ndr, t)); +} + +_PUBLIC_ void ndr_print_NTTIME_1sec(struct ndr_print *ndr, const char *name, NTTIME t) +{ + /* this is a standard NTTIME here + * as it's already converted in the pull/push code + */ + ndr_print_NTTIME(ndr, name, t); +} + +_PUBLIC_ void ndr_print_NTTIME_hyper(struct ndr_print *ndr, const char *name, NTTIME t) +{ + ndr_print_NTTIME(ndr, name, t); +} + +_PUBLIC_ void ndr_print_time_t(struct ndr_print *ndr, const char *name, time_t t) +{ + if (t == (time_t)-1 || t == 0) { + ndr->print(ndr, "%-25s: (time_t)%d", name, (int)t); + } else { + ndr->print(ndr, "%-25s: %s", name, timestring(ndr, t)); + } +} + +_PUBLIC_ void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type) +{ + if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) { + ndr->print(ndr, "%-25s: union %s(case 0x%X)", name, type, level); + } else { + ndr->print(ndr, "%-25s: union %s(case %d)", name, type, level); + } +} + +_PUBLIC_ void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level) +{ + ndr->print(ndr, "UNKNOWN LEVEL %u", level); +} + +_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, + const uint8_t *data, uint32_t count) +{ + int i; + + if (count <= 600 && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) { + char s[1202]; + for (i=0;i<count;i++) { + snprintf(&s[i*2], 3, "%02x", data[i]); + } + s[i*2] = 0; + ndr->print(ndr, "%-25s: %s", name, s); + return; + } + + ndr->print(ndr, "%s: ARRAY(%d)", name, count); + ndr->depth++; + for (i=0;i<count;i++) { + char *idx=NULL; + if (asprintf(&idx, "[%d]", i) != -1) { + ndr_print_uint8(ndr, idx, data[i]); + free(idx); + } + } + ndr->depth--; +} + +_PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r) +{ + ndr->print(ndr, "%-25s: DATA_BLOB length=%u", name, (unsigned)r.length); + if (r.length) { + dump_data(10, r.data, r.length); + } +} + + +/* + push a DATA_BLOB onto the wire. +*/ +_PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flags, DATA_BLOB blob) +{ + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + blob.length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + blob.length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + blob.length = NDR_ALIGN(ndr, 8); + } + NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length); + data_blob_clear(&blob); + } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, blob.length)); + } + NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length)); + return NDR_ERR_SUCCESS; +} + +/* + pull a DATA_BLOB from the wire. +*/ +_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_ALIGN_FLAGS) { + 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 if (ndr->flags & LIBNDR_FLAG_REMAINING) { + length = ndr->data_size - ndr->offset; + } else { + NDR_CHECK(ndr_pull_uint32(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; +} + +_PUBLIC_ uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, int flags) +{ + if (!data) return ret; + return ret + data->length; +} + +_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b) +{ + ndr->print(ndr, "%-25s: %s", name, b?"true":"false"); +} + +_PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss) +{ + char addr[INET6_ADDRSTRLEN]; + ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), ss)); +} diff --git a/source3/librpc/ndr/ndr_compression.c b/source3/librpc/ndr/ndr_compression.c new file mode 100644 index 0000000000..9da0773f28 --- /dev/null +++ b/source3/librpc/ndr/ndr_compression.c @@ -0,0 +1,293 @@ +/* + Unix SMB/CIFS implementation. + + libndr compression support + + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/compression/mszip.h" +#include "librpc/ndr/libndr.h" +#include "librpc/ndr/ndr_compression.h" + +static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + struct decomp_state *decomp_state, + bool *last) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_offset; + uint32_t comp_chunk_size; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_offset; + uint32_t plain_chunk_size; + int ret; + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size)); + if (plain_chunk_size > 0x00008000) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)", + plain_chunk_size); + } + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size)); + + DEBUG(10,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n", + plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size)); + + comp_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size)); + comp_chunk.length = comp_chunk_size; + comp_chunk.data = ndrpull->data + comp_chunk_offset; + + plain_chunk_offset = ndrpush->offset; + NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size)); + plain_chunk.length = plain_chunk_size; + plain_chunk.data = ndrpush->data + plain_chunk_offset; + + ret = ZIPdecompress(decomp_state, &comp_chunk, &plain_chunk); + if (ret != DECR_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZIPdecompress() error %d (PULL)", + ret); + } + + if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) { + /* this is the last chunk */ + *last = true; + } + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_compression_mszip(struct ndr_pull *subndr, + struct ndr_pull **_comndr, + ssize_t decompressed_len) +{ + struct ndr_push *ndrpush; + struct ndr_pull *comndr; + DATA_BLOB uncompressed; + uint32_t payload_header[4]; + uint32_t payload_size; + uint32_t payload_offset; + uint8_t *payload; + struct decomp_state *decomp_state; + bool last = false; + + ndrpush = ndr_push_init_ctx(subndr); + NDR_ERR_HAVE_NO_MEMORY(ndrpush); + + decomp_state = ZIPdecomp_state(subndr); + NDR_ERR_HAVE_NO_MEMORY(decomp_state); + + while (!last) { + NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, decomp_state, &last)); + } + + uncompressed = ndr_push_blob(ndrpush); + + if (uncompressed.length != decompressed_len) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP uncompressed_len [%u] != [%d] (PULL)", + (int)uncompressed.length, (int)decompressed_len); + } + + comndr = talloc_zero(subndr, struct ndr_pull); + NDR_ERR_HAVE_NO_MEMORY(comndr); + comndr->flags = subndr->flags; + comndr->current_mem_ctx = subndr->current_mem_ctx; + + comndr->data = uncompressed.data; + comndr->data_size = uncompressed.length; + comndr->offset = 0; + + NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0])); + NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1])); + NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2])); + NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3])); + + if (payload_header[0] != 0x00081001) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)", + payload_header[0]); + } + if (payload_header[1] != 0xCCCCCCCC) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)", + payload_header[1]); + } + + payload_size = payload_header[2]; + + if (payload_header[3] != 0x00000000) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)", + payload_header[3]); + } + + payload_offset = comndr->offset; + NDR_CHECK(ndr_pull_advance(comndr, payload_size)); + payload = comndr->data + payload_offset; + + comndr->data = payload; + comndr->data_size = payload_size; + comndr->offset = 0; + + *_comndr = comndr; + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_mszip(struct ndr_push *subndr, + struct ndr_push *comndr) +{ + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)"); +} + +static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + bool *last) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_offset; + uint32_t comp_chunk_size; + uint32_t plain_chunk_size; + + comp_chunk_offset = ndrpull->offset; + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size)); + if (plain_chunk_size > 0x00010000) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)", + plain_chunk_size); + } + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size)); + + NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size)); + comp_chunk.length = comp_chunk_size + 8; + comp_chunk.data = ndrpull->data + comp_chunk_offset; + + DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n", + plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size)); + + /* For now, we just copy over the compressed blob */ + NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length)); + + if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) { + /* this is the last chunk */ + *last = true; + } + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_compression_xpress(struct ndr_pull *subndr, + struct ndr_pull **_comndr, + ssize_t decompressed_len) +{ + struct ndr_push *ndrpush; + struct ndr_pull *comndr; + DATA_BLOB uncompressed; + bool last = false; + + ndrpush = ndr_push_init_ctx(subndr); + NDR_ERR_HAVE_NO_MEMORY(ndrpush); + + while (!last) { + NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last)); + } + + uncompressed = ndr_push_blob(ndrpush); + + comndr = talloc_zero(subndr, struct ndr_pull); + NDR_ERR_HAVE_NO_MEMORY(comndr); + comndr->flags = subndr->flags; + comndr->current_mem_ctx = subndr->current_mem_ctx; + + comndr->data = uncompressed.data; + comndr->data_size = uncompressed.length; + comndr->offset = 0; + + *_comndr = comndr; + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_xpress(struct ndr_push *subndr, + struct ndr_push *comndr) +{ + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)"); +} + +/* + handle compressed subcontext buffers, which in midl land are user-marshalled, but + we use magic in pidl to make them easier to cope with +*/ +enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr, + struct ndr_pull **_comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len) +{ + switch (compression_alg) { + case NDR_COMPRESSION_MSZIP: + return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len); + case NDR_COMPRESSION_XPRESS: + return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len); + default: + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)", + compression_alg); + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr, + struct ndr_pull *comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len) +{ + return NDR_ERR_SUCCESS; +} + +/* + push a compressed subcontext +*/ +enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr, + struct ndr_push **_comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len) +{ + struct ndr_push *comndr; + + comndr = ndr_push_init_ctx(subndr); + NDR_ERR_HAVE_NO_MEMORY(comndr); + comndr->flags = subndr->flags; + + *_comndr = comndr; + return NDR_ERR_SUCCESS; +} + +/* + push a compressed subcontext +*/ +enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr, + struct ndr_push *comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len) +{ + switch (compression_alg) { + case NDR_COMPRESSION_MSZIP: + return ndr_push_compression_mszip(subndr, comndr); + case NDR_COMPRESSION_XPRESS: + return ndr_push_compression_xpress(subndr, comndr); + default: + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)", + compression_alg); + } + return NDR_ERR_SUCCESS; +} diff --git a/source3/librpc/ndr/ndr_compression.h b/source3/librpc/ndr/ndr_compression.h new file mode 100644 index 0000000000..4cebbe190c --- /dev/null +++ b/source3/librpc/ndr/ndr_compression.h @@ -0,0 +1,51 @@ +#ifndef __LIBRPC_NDR_NDR_COMPRESSION_H__ +#define __LIBRPC_NDR_NDR_COMPRESSION_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +#ifndef _PUBLIC_ +#define _PUBLIC_ +#endif + +#ifndef _PURE_ +#define _PURE_ +#endif + +#ifndef _NORETURN_ +#define _NORETURN_ +#endif + +#ifndef _DEPRECATED_ +#define _DEPRECATED_ +#endif + +#ifndef _WARN_UNUSED_RESULT_ +#define _WARN_UNUSED_RESULT_ +#endif + + +/* The following definitions come from librpc/ndr/ndr_compression.c */ + +enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr, + struct ndr_pull **_comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len); +enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr, + struct ndr_pull *comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len); +enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr, + struct ndr_push **_comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len); +enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr, + struct ndr_push *comndr, + enum ndr_compression_alg compression_alg, + ssize_t decompressed_len); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __LIBRPC_NDR_NDR_COMPRESSION_H__ */ + diff --git a/source3/librpc/ndr/ndr_drsuapi.c b/source3/librpc/ndr/ndr_drsuapi.c new file mode 100644 index 0000000000..aeb81c87bd --- /dev/null +++ b/source3/librpc/ndr/ndr_drsuapi.c @@ -0,0 +1,177 @@ +/* + Unix SMB/CIFS implementation. + + routines for printing some linked list structs in DRSUAPI + + Copyright (C) Stefan (metze) Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_misc.h" + +void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name, + const struct drsuapi_DsReplicaObjectListItem *r) +{ + ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItem"); + ndr->depth++; + ndr_print_ptr(ndr, "next_object", r->next_object); + ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object); + ndr->depth--; + if (r->next_object) { + ndr_print_drsuapi_DsReplicaObjectListItem(ndr, "next_object", r->next_object); + } +} + +void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItemEx *r) +{ + ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItemEx"); + ndr->depth++; + ndr_print_ptr(ndr, "next_object", r->next_object); + ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object); + ndr_print_uint32(ndr, "is_nc_prefix", r->is_nc_prefix); + ndr_print_ptr(ndr, "parent_object_guid", r->parent_object_guid); + ndr->depth++; + if (r->parent_object_guid) { + ndr_print_GUID(ndr, "parent_object_guid", r->parent_object_guid); + } + ndr->depth--; + ndr_print_ptr(ndr, "meta_data_ctr", r->meta_data_ctr); + ndr->depth++; + if (r->meta_data_ctr) { + ndr_print_drsuapi_DsReplicaMetaDataCtr(ndr, "meta_data_ctr", r->meta_data_ctr); + } + ndr->depth--; + ndr->depth--; + if (r->next_object) { + ndr_print_drsuapi_DsReplicaObjectListItemEx(ndr, "next_object", r->next_object); + } +} + +#define _OID_PUSH_CHECK(call) do { \ + bool _status; \ + _status = call; \ + if (_status != true) { \ + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "OID Conversion Error: %s\n", __location__); \ + } \ +} while (0) + +#define _OID_PULL_CHECK(call) do { \ + bool _status; \ + _status = call; \ + if (_status != true) { \ + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "OID Conversion Error: %s\n", __location__); \ + } \ +} while (0) + +enum ndr_err_code ndr_push_drsuapi_DsReplicaOID(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOID *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_drsuapi_DsReplicaOID_oid(r->oid, 0))); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->oid)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->oid) { + DATA_BLOB blob; + + if (StrnCaseCmp("ff", r->oid, 2) == 0) { + blob = strhex_to_data_blob(NULL, r->oid); + if (!blob.data) { + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, + "HEX String Conversion Error: %s\n", + __location__); + } + } else { + _OID_PUSH_CHECK(ber_write_OID_String(&blob, r->oid)); + } + talloc_steal(ndr, blob.data); + + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, blob.length)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, blob.data, blob.length)); + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_drsuapi_DsReplicaOID(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOID *r) +{ + uint32_t _ptr_oid; + TALLOC_CTX *_mem_save_oid_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->__ndr_size)); + if (r->__ndr_size < 0 || r->__ndr_size > 10000) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range"); + } + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_oid)); + if (_ptr_oid) { + NDR_PULL_ALLOC(ndr, r->oid); + } else { + r->oid = NULL; + } + } + if (ndr_flags & NDR_BUFFERS) { + if (r->oid) { + DATA_BLOB _oid_array; + const char *_oid; + + _mem_save_oid_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, ndr, 0); + NDR_CHECK(ndr_pull_array_size(ndr, &r->oid)); + _oid_array.length = ndr_get_array_size(ndr, &r->oid); + NDR_PULL_ALLOC_N(ndr, _oid_array.data, _oid_array.length); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, _oid_array.data, _oid_array.length)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_oid_0, 0); + + if (_oid_array.length && _oid_array.data[0] == 0xFF) { + _oid = data_blob_hex_string(ndr, &_oid_array); + NDR_ERR_HAVE_NO_MEMORY(_oid); + } else { + _OID_PULL_CHECK(ber_read_OID_String(ndr, _oid_array, &_oid)); + } + TALLOC_FREE(_oid_array.data); + talloc_steal(r->oid, _oid); + r->oid = _oid; + } + if (r->oid) { + NDR_CHECK(ndr_check_array_size(ndr, (void*)&r->oid, r->__ndr_size)); + } + } + return NDR_ERR_SUCCESS; +} + +size_t ndr_size_drsuapi_DsReplicaOID_oid(const char *oid, int flags) +{ + DATA_BLOB _blob; + size_t ret = 0; + + if (!oid) return 0; + + if (StrnCaseCmp("ff", oid, 2) == 0) { + _blob = strhex_to_data_blob(NULL, oid); + if (_blob.data) { + ret = _blob.length; + } + } else { + if (ber_write_OID_String(&_blob, oid)) { + ret = _blob.length; + } + } + data_blob_free(&_blob); + return ret; +} diff --git a/source3/librpc/ndr/ndr_drsuapi.h b/source3/librpc/ndr/ndr_drsuapi.h new file mode 100644 index 0000000000..c663eadd7a --- /dev/null +++ b/source3/librpc/ndr/ndr_drsuapi.h @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + routines for printing some linked list structs in DRSUAPI + + Copyright (C) Stefan (metze) Metzmacher 2005-2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LIBRPC_NDR_NDR_DRSUAPI_H +#define _LIBRPC_NDR_NDR_DRSUAPI_H + +void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name, + const struct drsuapi_DsReplicaObjectListItem *r); + +void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name, + const struct drsuapi_DsReplicaObjectListItemEx *r); + +enum ndr_err_code ndr_push_drsuapi_DsReplicaOID(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsReplicaOID *r); +enum ndr_err_code ndr_pull_drsuapi_DsReplicaOID(struct ndr_pull *ndr, int ndr_flags, struct drsuapi_DsReplicaOID *r); +size_t ndr_size_drsuapi_DsReplicaOID_oid(const char *oid, int flags); + +#endif /* _LIBRPC_NDR_NDR_DRSUAPI_H */ diff --git a/source3/librpc/ndr/ndr_krb5pac.c b/source3/librpc/ndr/ndr_krb5pac.c new file mode 100644 index 0000000000..b0eab44012 --- /dev/null +++ b/source3/librpc/ndr/ndr_krb5pac.c @@ -0,0 +1,141 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling spoolss subcontext buffer structures + + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "includes.h" + +#include "librpc/gen_ndr/ndr_krb5pac.h" + +static size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags) +{ + size_t s = ndr_size_PAC_INFO(r, level, flags); + switch (level) { + case PAC_TYPE_LOGON_INFO: + return NDR_ROUND(s,8); + default: + return s; + } +} + +static size_t _subcontext_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, int flags) +{ + size_t s = ndr_size_PAC_INFO(r, level, flags); + return NDR_ROUND(s,8); +} + +enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const struct PAC_BUFFER *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0))); + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->info)); + ndr->flags = _flags_save_PAC_INFO; + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + } + if (ndr_flags & NDR_BUFFERS) { + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); + if (r->info) { + NDR_CHECK(ndr_push_relative_ptr2(ndr, r->info)); + { + struct ndr_push *_ndr_info; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info, 0, _subcontext_size_PAC_INFO(r->info,r->type,0))); + NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type)); + NDR_CHECK(ndr_push_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info, 0, _subcontext_size_PAC_INFO(r->info,r->type,0))); + } + } + ndr->flags = _flags_save_PAC_INFO; + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER *r) +{ + uint32_t _ptr_info; + TALLOC_CTX *_mem_save_info_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_PAC_TYPE(ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_ndr_size)); + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info)); + if (_ptr_info) { + NDR_PULL_ALLOC(ndr, r->info); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->info, _ptr_info)); + } else { + r->info = NULL; + } + ndr->flags = _flags_save_PAC_INFO; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_pad)); + } + if (ndr_flags & NDR_BUFFERS) { + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); + if (r->info) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->info)); + _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->info, 0); + { + struct ndr_pull *_ndr_info; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info, 0, r->_ndr_size)); + NDR_CHECK(ndr_pull_set_switch_value(_ndr_info, r->info, r->type)); + NDR_CHECK(ndr_pull_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info, 0, r->_ndr_size)); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0); + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_PAC_INFO; + } + } + return NDR_ERR_SUCCESS; +} + +void ndr_print_PAC_BUFFER(struct ndr_print *ndr, const char *name, const struct PAC_BUFFER *r) +{ + ndr_print_struct(ndr, name, "PAC_BUFFER"); + ndr->depth++; + ndr_print_PAC_TYPE(ndr, "type", r->type); + ndr_print_uint32(ndr, "_ndr_size", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?_ndr_size_PAC_INFO(r->info,r->type,0):r->_ndr_size); + ndr_print_ptr(ndr, "info", r->info); + ndr->depth++; + if (r->info) { + ndr_print_set_switch_value(ndr, r->info, r->type); + ndr_print_PAC_INFO(ndr, "info", r->info); + } + ndr->depth--; + ndr_print_uint32(ndr, "_pad", r->_pad); + ndr->depth--; +} diff --git a/source3/librpc/ndr/ndr_misc.c b/source3/librpc/ndr/ndr_misc.c new file mode 100644 index 0000000000..e86842527c --- /dev/null +++ b/source3/librpc/ndr/ndr_misc.c @@ -0,0 +1,94 @@ +/* + Unix SMB/CIFS implementation. + + UUID/GUID/policy_handle functions + + Copyright (C) Theodore Ts'o 1996, 1997, + Copyright (C) Jim McDonough 2002. + Copyright (C) Andrew Tridgell 2003. + Copyright (C) Stefan (metze) Metzmacher 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" + +/** + * see if a range of memory is all zero. A NULL pointer is considered + * to be all zero + */ +bool all_zero(const uint8_t *ptr, size_t size) +{ + int i; + if (!ptr) return True; + for (i=0;i<size;i++) { + if (ptr[i]) return False; + } + return True; +} + +void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid) +{ + ndr->print(ndr, "%-25s: %s", name, GUID_string(ndr, guid)); +} + +bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1, + const struct ndr_syntax_id *i2) +{ + return GUID_equal(&i1->uuid, &i2->uuid) + && (i1->if_version == i2->if_version); +} + +enum ndr_err_code ndr_push_server_id(struct ndr_push *ndr, int ndr_flags, const struct server_id *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, + (uint32_t)r->pid)); +#ifdef CLUSTER_SUPPORT + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, + (uint32_t)r->vnn)); +#endif + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_server_id(struct ndr_pull *ndr, int ndr_flags, struct server_id *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t pid; + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pid)); +#ifdef CLUSTER_SUPPORT + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->vnn)); +#endif + r->pid = (pid_t)pid; + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +void ndr_print_server_id(struct ndr_print *ndr, const char *name, const struct server_id *r) +{ + ndr_print_struct(ndr, name, "server_id"); + ndr->depth++; + ndr_print_uint32(ndr, "id", (uint32_t)r->pid); +#ifdef CLUSTER_SUPPORT + ndr_print_uint32(ndr, "vnn", (uint32_t)r->vnn); +#endif + ndr->depth--; +} diff --git a/source3/librpc/ndr/ndr_sec.h b/source3/librpc/ndr/ndr_sec.h new file mode 100644 index 0000000000..8034367223 --- /dev/null +++ b/source3/librpc/ndr/ndr_sec.h @@ -0,0 +1,35 @@ +#ifndef __LIBRPC_NDR_NDR_SEC_H__ +#define __LIBRPC_NDR_NDR_SEC_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +#ifndef _PUBLIC_ +#define _PUBLIC_ +#endif + + +/* The following definitions come from librpc/ndr/ndr_sec_helper.c */ + +size_t ndr_size_dom_sid(const struct dom_sid *sid); +size_t ndr_length_dom_sid(const struct dom_sid *sid); +size_t ndr_size_security_ace(const struct security_ace *ace); +size_t ndr_size_security_acl(const struct security_acl *acl); +size_t ndr_size_security_descriptor(const struct security_descriptor *sd); +void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); + +/* The following definitions come from librpc/ndr/ndr_sec.c */ + +enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid); +enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid); +enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid); +enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __LIBRPC_NDR_NDR_SEC_H__ */ + diff --git a/source3/librpc/ndr/ndr_sec_helper.c b/source3/librpc/ndr/ndr_sec_helper.c new file mode 100644 index 0000000000..18d343799e --- /dev/null +++ b/source3/librpc/ndr/ndr_sec_helper.c @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + + fast routines for getting the wire size of security objects + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "includes.h" + +/* + return the wire size of a dom_sid +*/ +size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags) +{ + if (!sid) return 0; + return 8 + 4*sid->num_auths; +} + +size_t ndr_size_dom_sid28(const struct dom_sid *sid, int flags) +{ + struct dom_sid zero_sid; + + if (!sid) return 0; + + ZERO_STRUCT(zero_sid); + + if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) { + return 0; + } + + return 8 + 4*sid->num_auths; +} + +size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags) +{ + return ndr_size_dom_sid28(sid, flags); +} + +/* + return the wire size of a security_ace +*/ +size_t ndr_size_security_ace(const struct security_ace *ace, int flags) +{ + if (!ace) return 0; + return 8 + ndr_size_dom_sid(&ace->trustee, flags); +} + + +/* + return the wire size of a security_acl +*/ +size_t ndr_size_security_acl(const struct security_acl *acl, int flags) +{ + size_t ret; + int i; + if (!acl) return 0; + ret = 8; + for (i=0;i<acl->num_aces;i++) { + ret += ndr_size_security_ace(&acl->aces[i], flags); + } + return ret; +} + +/* + return the wire size of a security descriptor +*/ +size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags) +{ + size_t ret; + if (!sd) return 0; + + ret = 20; + ret += ndr_size_dom_sid(sd->owner_sid, flags); + ret += ndr_size_dom_sid(sd->group_sid, flags); + ret += ndr_size_security_acl(sd->dacl, flags); + ret += ndr_size_security_acl(sd->sacl, flags); + return ret; +} + +/* + print a dom_sid +*/ +void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr->print(ndr, "%-25s: %s", name, dom_sid_string(ndr, sid)); +} + +void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr_print_dom_sid(ndr, name, sid); +} + +void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr_print_dom_sid(ndr, name, sid); +} + +void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr_print_dom_sid(ndr, name, sid); +} + diff --git a/source3/librpc/ndr/ndr_string.c b/source3/librpc/ndr/ndr_string.c new file mode 100644 index 0000000000..e2c9ed5946 --- /dev/null +++ b/source3/librpc/ndr/ndr_string.c @@ -0,0 +1,738 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling string types + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "librpc/ndr/libndr.h" + +/** + pull a general string from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) +{ + char *as=NULL; + uint32_t len1, ofs, len2; + uint16_t len3; + size_t converted_size; + int chset = CH_UTF16; + unsigned byte_mul = 2; + unsigned flags = ndr->flags; + unsigned c_len_term = 0; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + chset = CH_UTF16BE; + } + + if (flags & LIBNDR_FLAG_STR_ASCII) { + chset = CH_DOS; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_ASCII; + } + + if (flags & LIBNDR_FLAG_STR_UTF8) { + chset = CH_UTF8; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_UTF8; + } + + flags &= ~LIBNDR_FLAG_STR_CONFORMANT; + if (flags & LIBNDR_FLAG_STR_CHARLEN) { + c_len_term = 1; + flags &= ~LIBNDR_FLAG_STR_CHARLEN; + } + + switch (flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); + if (ofs != 0) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2)); + if (len2 > len1) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "Bad string lengths len1=%u ofs=%u len2=%u\n", + len1, ofs, len2); + } + NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul); + if (len2 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, + (len2 + c_len_term)*byte_mul, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul)); + + if (len1 != len2) { + DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as)); + } + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len2 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len2 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); + if (len1 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, + (len1 + c_len_term)*byte_mul, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len1 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len1 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_LEN4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); + if (ofs != 0) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); + if (len1 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, + (len1 + c_len_term)*byte_mul, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len1 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len1 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + + case LIBNDR_FLAG_STR_SIZE2: + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul); + if (len3 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, + (len3 + c_len_term)*byte_mul, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len3 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len3 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + NDR_PULL_NEED_BYTES(ndr, len3); + if (len3 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, len3, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, len3)); + *s = as; + break; + + case LIBNDR_FLAG_STR_NULLTERM: + if (byte_mul == 1) { + len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); + } else { + len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); + } + if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, + ndr->data+ndr->offset, len1, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, len1)); + *s = as; + break; + + case LIBNDR_FLAG_STR_FIXLEN15: + case LIBNDR_FLAG_STR_FIXLEN32: + len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; + NDR_PULL_NEED_BYTES(ndr, len1*byte_mul); + if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, + ndr->data+ndr->offset, len1*byte_mul, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul)); + *s = as; + break; + + case LIBNDR_FLAG_STR_NOTERM: + if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + len1 = ndr->data_size - ndr->offset; + + NDR_PULL_NEED_BYTES(ndr, len1); + if (len1 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, + ndr->data+ndr->offset, len1, + (void **)(void *)&as, + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, len1)); + + *s = as; + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + return NDR_ERR_SUCCESS; +} + + +/** + push a general string onto the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) +{ + ssize_t s_len, c_len; + size_t d_len; + int chset = CH_UTF16; + unsigned flags = ndr->flags; + unsigned byte_mul = 2; + uint8_t *dest = NULL; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + chset = CH_UTF16BE; + } + + s_len = s?strlen(s):0; + + if (flags & LIBNDR_FLAG_STR_ASCII) { + chset = CH_DOS; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_ASCII; + } + + if (flags & LIBNDR_FLAG_STR_UTF8) { + chset = CH_UTF8; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_UTF8; + } + + flags &= ~LIBNDR_FLAG_STR_CONFORMANT; + + if (!(flags & + (LIBNDR_FLAG_STR_NOTERM | + LIBNDR_FLAG_STR_FIXLEN15 | + LIBNDR_FLAG_STR_FIXLEN32))) { + s_len++; + } + if (!convert_string_talloc(ndr, CH_UNIX, chset, s, s_len, + (void **)(void *)&dest, &d_len, false)) + { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + + if (flags & LIBNDR_FLAG_STR_BYTESIZE) { + c_len = d_len; + flags &= ~LIBNDR_FLAG_STR_BYTESIZE; + } else if (flags & LIBNDR_FLAG_STR_CHARLEN) { + c_len = (d_len / byte_mul)-1; + flags &= ~LIBNDR_FLAG_STR_CHARLEN; + } else { + c_len = d_len / byte_mul; + } + + switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) { + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_LEN4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_SIZE4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_NULLTERM: + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_FIXLEN15: + case LIBNDR_FLAG_STR_FIXLEN32: { + ssize_t fix_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; + uint32_t pad_len = fix_len - d_len; + if (d_len > fix_len) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + if (pad_len != 0) { + NDR_CHECK(ndr_push_zero(ndr, pad_len)); + } + break; + } + + default: + if (ndr->flags & LIBNDR_FLAG_REMAINING) { + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + } + + return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + talloc_free(dest); + + return NDR_ERR_SUCCESS; +} + +/** + push a general string onto the wire +*/ +_PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s) +{ + size_t c_len; + unsigned flags = ndr->flags; + unsigned byte_mul = 2; + unsigned c_len_term = 1; + + if (flags & LIBNDR_FLAG_STR_FIXLEN32) { + return 32; + } + if (flags & LIBNDR_FLAG_STR_FIXLEN15) { + return 15; + } + + c_len = s?strlen_m(s):0; + + if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) { + byte_mul = 1; + } + + if (flags & LIBNDR_FLAG_STR_NOTERM) { + c_len_term = 0; + } + + c_len = c_len + c_len_term; + + if (flags & LIBNDR_FLAG_STR_BYTESIZE) { + c_len = c_len * byte_mul; + } + + return c_len; +} + +_PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s) +{ + if (s) { + ndr->print(ndr, "%-25s: '%s'", name, s); + } else { + ndr->print(ndr, "%-25s: NULL", name); + } +} + +_PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, int flags) +{ + /* FIXME: Is this correct for all strings ? */ + if(!(*string)) return ret; + return ret+strlen(*string)+1; +} + +/** + pull a general string array from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a) +{ + const char **a = *_a; + uint32_t count; + unsigned flags = ndr->flags; + unsigned saved_flags = ndr->flags; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + switch (flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_NULLTERM: + /* + * here the strings are null terminated + * but also the array is null terminated + */ + for (count = 0;; count++) { + TALLOC_CTX *tmp_ctx; + const char *s = NULL; + a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2); + NDR_ERR_HAVE_NO_MEMORY(a); + a[count] = NULL; + a[count+1] = NULL; + + tmp_ctx = ndr->current_mem_ctx; + ndr->current_mem_ctx = a; + NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); + ndr->current_mem_ctx = tmp_ctx; + if (strcmp("", s)==0) { + a[count] = NULL; + break; + } else { + a[count] = s; + } + } + + *_a =a; + break; + + case LIBNDR_FLAG_STR_NOTERM: + if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + /* + * here the strings are not null terminated + * but serarated by a null terminator + * + * which means the same as: + * very string is null terminated exept the last + * string is terminated by the end of the buffer + * + * as LIBNDR_FLAG_STR_NULLTERM also end at the end + * of the buffer, we can pull each string with this flag + */ + ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING); + ndr->flags |= LIBNDR_FLAG_STR_NULLTERM; + + for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) { + TALLOC_CTX *tmp_ctx; + const char *s = NULL; + a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2); + NDR_ERR_HAVE_NO_MEMORY(a); + a[count] = NULL; + a[count+1] = NULL; + + tmp_ctx = ndr->current_mem_ctx; + ndr->current_mem_ctx = a; + NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); + ndr->current_mem_ctx = tmp_ctx; + a[count] = s; + } + + *_a =a; + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + ndr->flags = saved_flags; + return NDR_ERR_SUCCESS; +} + +/** + push a general string array onto the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a) +{ + uint32_t count; + unsigned flags = ndr->flags; + unsigned saved_flags = ndr->flags; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + switch (flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_NULLTERM: + for (count = 0; a && a[count]; count++) { + NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); + } + + NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); + break; + + case LIBNDR_FLAG_STR_NOTERM: + if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x (missing NDR_REMAINING)\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + for (count = 0; a && a[count]; count++) { + if (count > 0) { + ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING); + ndr->flags |= LIBNDR_FLAG_STR_NULLTERM; + NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); + ndr->flags = saved_flags; + } + NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); + } + + break; + + default: + return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + ndr->flags = saved_flags; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a) +{ + uint32_t count; + uint32_t i; + + for (count = 0; a && a[count]; count++) {} + + ndr->print(ndr, "%s: ARRAY(%d)", name, count); + ndr->depth++; + for (i=0;i<count;i++) { + char *idx=NULL; + if (asprintf(&idx, "[%d]", i) != -1) { + ndr_print_string(ndr, idx, a[i]); + free(idx); + } + } + ndr->depth--; +} + +/** + * Return number of elements in a string including the last (zeroed) element + */ +_PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size) +{ + uint32_t i; + uint8_t zero[4] = {0,0,0,0}; + const char *var = (const char *)_var; + + for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++); + + return i+1; +} + +_PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) +{ + uint32_t i; + struct ndr_pull_save save_offset; + + ndr_pull_save(ndr, &save_offset); + ndr_pull_advance(ndr, (count - 1) * element_size); + NDR_PULL_NEED_BYTES(ndr, element_size); + + for (i = 0; i < element_size; i++) { + if (ndr->data[ndr->offset+i] != 0) { + ndr_pull_restore(ndr, &save_offset); + + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); + } + } + + ndr_pull_restore(ndr, &save_offset); + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) +{ + size_t converted_size; + + if (length == 0) { + *var = talloc_strdup(ndr->current_mem_ctx, ""); + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr) && chset == CH_UTF16) { + chset = CH_UTF16BE; + } + + NDR_PULL_NEED_BYTES(ndr, length*byte_mul); + + if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, + ndr->data+ndr->offset, length*byte_mul, + discard_const_p(void *, var), + &converted_size, false)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset) +{ + ssize_t ret, required; + + if (NDR_BE(ndr) && chset == CH_UTF16) { + chset = CH_UTF16BE; + } + + required = byte_mul * length; + + NDR_PUSH_NEED_BYTES(ndr, required); + ret = convert_string(CH_UNIX, chset, + var, strlen(var), + ndr->data+ndr->offset, required, false); + if (ret == -1) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad char conversion"); + } + + /* Make sure the remaining part of the string is filled with zeroes */ + if (ret < required) { + memset(ndr->data+ndr->offset+ret, 0, required-ret); + } + + ndr->offset += required; + + return NDR_ERR_SUCCESS; +} + +/* Return number of elements in a string in the specified charset */ +_PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset) +{ + /* FIXME: Treat special chars special here, taking chset into account */ + /* Also include 0 byte */ + return strlen((const char *)var)+1; +} diff --git a/source3/librpc/ndr/sid.c b/source3/librpc/ndr/sid.c new file mode 100644 index 0000000000..ed27375de1 --- /dev/null +++ b/source3/librpc/ndr/sid.c @@ -0,0 +1,230 @@ +/* + Unix SMB/CIFS implementation. + + libndr interface + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" + +enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *r) +{ + uint32_t cntr_sub_auths_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num)); + NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *r) +{ + uint32_t cntr_sub_auths_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num)); + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_auths)); + if (r->num_auths > 15) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range"); + } + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) { + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +/* + convert a dom_sid to a string +*/ +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid) +{ + int i, ofs, maxlen; + uint32_t ia; + char *ret; + + if (!sid) { + return talloc_strdup(mem_ctx, "(NULL SID)"); + } + + maxlen = sid->num_auths * 11 + 25; + ret = (char *)talloc_size(mem_ctx, maxlen); + if (!ret) return talloc_strdup(mem_ctx, "(SID ERR)"); + + /* + * BIG NOTE: this function only does SIDS where the identauth is not + * >= ^32 in a range of 2^48. + */ + + ia = (sid->id_auth[5]) + + (sid->id_auth[4] << 8 ) + + (sid->id_auth[3] << 16) + + (sid->id_auth[2] << 24); + + ofs = snprintf(ret, maxlen, "S-%u-%lu", + (unsigned int)sid->sid_rev_num, (unsigned long)ia); + + for (i = 0; i < sid->num_auths; i++) { + ofs += snprintf(ret + ofs, maxlen - ofs, "-%lu", (unsigned long)sid->sub_auths[i]); + } + + return ret; +} + +/* + 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_uint32(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; +} + +/* + parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field +*/ +enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, sid->num_auths)); + return ndr_push_dom_sid(ndr, ndr_flags, sid); +} + +/* + 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); + } + + return NDR_ERR_SUCCESS; +} + +/* + push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer +*/ +enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid) +{ + uint32_t old_offset; + uint32_t padding; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (sid->num_auths > 5) { + return ndr_push_error(ndr, NDR_ERR_RANGE, + "dom_sid28 allows only upto 5 sub auth [%u]", + sid->num_auths); + } + + old_offset = ndr->offset; + NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid)); + + padding = 28 - (ndr->offset - old_offset); + + if (padding > 0) { + NDR_CHECK(ndr_push_zero(ndr, padding)); + } + + return NDR_ERR_SUCCESS; +} + +/* + parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty +*/ +enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (ndr->data_size == ndr->offset) { + ZERO_STRUCTP(sid); + return NDR_ERR_SUCCESS; + } + + return ndr_pull_dom_sid(ndr, ndr_flags, sid); +} + +/* + push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty +*/ +enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid) +{ + struct dom_sid zero_sid; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (!sid) { + return NDR_ERR_SUCCESS; + } + + ZERO_STRUCT(zero_sid); + + if (memcmp(&zero_sid, sid, sizeof(zero_sid)) == 0) { + return NDR_ERR_SUCCESS; + } + + return ndr_push_dom_sid(ndr, ndr_flags, sid); +} diff --git a/source3/librpc/ndr/uuid.c b/source3/librpc/ndr/uuid.c new file mode 100644 index 0000000000..e92df22494 --- /dev/null +++ b/source3/librpc/ndr/uuid.c @@ -0,0 +1,227 @@ +/* + Unix SMB/CIFS implementation. + + UUID/GUID functions + + Copyright (C) Theodore Ts'o 1996, 1997, + Copyright (C) Jim McDonough 2002. + Copyright (C) Andrew Tridgell 2003. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "librpc/ndr/libndr.h" + +/** + build a GUID from a string +*/ +_PUBLIC_ NTSTATUS GUID_from_string(const char *s, struct GUID *guid) +{ + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; + uint32_t time_low; + uint32_t time_mid, time_hi_and_version; + uint32_t clock_seq[2]; + uint32_t node[6]; + int i; + + if (s == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (11 == sscanf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq[0], &clock_seq[1], + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + status = NT_STATUS_OK; + } else if (11 == sscanf(s, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq[0], &clock_seq[1], + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + status = NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + guid->time_low = time_low; + guid->time_mid = time_mid; + guid->time_hi_and_version = time_hi_and_version; + guid->clock_seq[0] = clock_seq[0]; + guid->clock_seq[1] = clock_seq[1]; + for (i=0;i<6;i++) { + guid->node[i] = node[i]; + } + + return NT_STATUS_OK; +} + +/** + build a GUID from a string +*/ +_PUBLIC_ NTSTATUS NS_GUID_from_string(const char *s, struct GUID *guid) +{ + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; + uint32_t time_low; + uint32_t time_mid, time_hi_and_version; + uint32_t clock_seq[2]; + uint32_t node[6]; + int i; + + if (s == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (11 == sscanf(s, "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq[0], &clock_seq[1], + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + status = NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + guid->time_low = time_low; + guid->time_mid = time_mid; + guid->time_hi_and_version = time_hi_and_version; + guid->clock_seq[0] = clock_seq[0]; + guid->clock_seq[1] = clock_seq[1]; + for (i=0;i<6;i++) { + guid->node[i] = node[i]; + } + + return NT_STATUS_OK; +} + +/** + * generate a random GUID + */ +struct GUID GUID_random(void) +{ + struct GUID guid; + + generate_random_buffer((uint8_t *)&guid, sizeof(guid)); + guid.clock_seq[0] = (guid.clock_seq[0] & 0x3F) | 0x80; + guid.time_hi_and_version = (guid.time_hi_and_version & 0x0FFF) | 0x4000; + + return guid; +} + +/** + * generate an empty GUID + */ +_PUBLIC_ struct GUID GUID_zero(void) +{ + struct GUID guid; + + ZERO_STRUCT(guid); + + return guid; +} + +_PUBLIC_ bool GUID_all_zero(const struct GUID *u) +{ + if (u->time_low != 0 || + u->time_mid != 0 || + u->time_hi_and_version != 0 || + u->clock_seq[0] != 0 || + u->clock_seq[1] != 0 || + !all_zero(u->node, 6)) { + return false; + } + return true; +} + +_PUBLIC_ bool GUID_equal(const struct GUID *u1, const struct GUID *u2) +{ + if (u1->time_low != u2->time_low || + u1->time_mid != u2->time_mid || + u1->time_hi_and_version != u2->time_hi_and_version || + u1->clock_seq[0] != u2->clock_seq[0] || + u1->clock_seq[1] != u2->clock_seq[1] || + memcmp(u1->node, u2->node, 6) != 0) { + return false; + } + return true; +} + +_PUBLIC_ int GUID_compare(const struct GUID *u1, const struct GUID *u2) +{ + if (u1->time_low != u2->time_low) { + return u1->time_low - u2->time_low; + } + + if (u1->time_mid != u2->time_mid) { + return u1->time_mid - u2->time_mid; + } + + if (u1->time_hi_and_version != u2->time_hi_and_version) { + return u1->time_hi_and_version - u2->time_hi_and_version; + } + + if (u1->clock_seq[0] != u2->clock_seq[0]) { + return u1->clock_seq[0] - u2->clock_seq[0]; + } + + if (u1->clock_seq[1] != u2->clock_seq[1]) { + return u1->clock_seq[1] - u2->clock_seq[1]; + } + + return memcmp(u1->node, u2->node, 6); +} + +/** + its useful to be able to display these in debugging messages +*/ +_PUBLIC_ char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + return talloc_asprintf(mem_ctx, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->time_low, guid->time_mid, + guid->time_hi_and_version, + guid->clock_seq[0], + guid->clock_seq[1], + guid->node[0], guid->node[1], + guid->node[2], guid->node[3], + guid->node[4], guid->node[5]); +} + +_PUBLIC_ char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + char *ret, *s = GUID_string(mem_ctx, guid); + ret = talloc_asprintf(mem_ctx, "{%s}", s); + talloc_free(s); + return ret; +} + +_PUBLIC_ char *NS_GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + return talloc_asprintf(mem_ctx, + "%08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x", + guid->time_low, guid->time_mid, + guid->time_hi_and_version, + guid->clock_seq[0], + guid->clock_seq[1], + guid->node[0], guid->node[1], + guid->node[2], guid->node[3], + guid->node[4], guid->node[5]); +} + +_PUBLIC_ bool policy_handle_empty(struct policy_handle *h) +{ + return (h->handle_type == 0 && GUID_all_zero(&h->uuid)); +} |