From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- librpc/ndr/libndr.h | 918 +++++++++++++++++++ librpc/ndr/ndr.c | 2040 ++++++++++++++++++++++++++++++++++++++++++ librpc/ndr/ndr_ODJ.c | 65 ++ librpc/ndr/ndr_ODJ.h | 22 + librpc/ndr/ndr_auth.c | 44 + librpc/ndr/ndr_auth.h | 32 + librpc/ndr/ndr_backupkey.c | 222 +++++ librpc/ndr/ndr_backupkey.h | 23 + librpc/ndr/ndr_basic.c | 1596 +++++++++++++++++++++++++++++++++ librpc/ndr/ndr_bkupblobs.c | 82 ++ librpc/ndr/ndr_cab.c | 442 +++++++++ librpc/ndr/ndr_cab.h | 22 + librpc/ndr/ndr_claims.c | 90 ++ librpc/ndr/ndr_claims.h | 34 + librpc/ndr/ndr_compression.c | 1092 ++++++++++++++++++++++ librpc/ndr/ndr_compression.h | 60 ++ librpc/ndr/ndr_dcerpc.c | 316 +++++++ librpc/ndr/ndr_dcerpc.h | 29 + librpc/ndr/ndr_dns.c | 327 +++++++ librpc/ndr/ndr_dns.h | 40 + librpc/ndr/ndr_dns_utils.c | 134 +++ librpc/ndr/ndr_dns_utils.h | 6 + librpc/ndr/ndr_dnsp.c | 263 ++++++ librpc/ndr/ndr_dnsp.h | 33 + librpc/ndr/ndr_dnsserver.c | 100 +++ librpc/ndr/ndr_dnsserver.h | 25 + librpc/ndr/ndr_drsblobs.c | 220 +++++ librpc/ndr/ndr_drsblobs.h | 23 + librpc/ndr/ndr_drsuapi.c | 577 ++++++++++++ librpc/ndr/ndr_drsuapi.h | 34 + librpc/ndr/ndr_frsrpc.c | 92 ++ librpc/ndr/ndr_frsrpc.h | 34 + librpc/ndr/ndr_ioctl.c | 40 + librpc/ndr/ndr_krb5pac.c | 130 +++ librpc/ndr/ndr_krb5pac.h | 25 + librpc/ndr/ndr_misc.c | 77 ++ librpc/ndr/ndr_nbt.c | 406 +++++++++ librpc/ndr/ndr_nbt.h | 42 + librpc/ndr/ndr_negoex.c | 521 +++++++++++ librpc/ndr/ndr_negoex.h | 37 + librpc/ndr/ndr_netlogon.c | 65 ++ librpc/ndr/ndr_netlogon.h | 28 + librpc/ndr/ndr_ntlmssp.c | 195 ++++ librpc/ndr/ndr_ntlmssp.h | 35 + librpc/ndr/ndr_ntprinting.c | 87 ++ librpc/ndr/ndr_ntprinting.h | 27 + librpc/ndr/ndr_orpc.c | 163 ++++ librpc/ndr/ndr_preg.c | 69 ++ librpc/ndr/ndr_preg.h | 23 + librpc/ndr/ndr_private.h | 32 + librpc/ndr/ndr_rap.c | 28 + librpc/ndr/ndr_rap.h | 22 + librpc/ndr/ndr_schannel.c | 107 +++ librpc/ndr/ndr_schannel.h | 25 + librpc/ndr/ndr_sec_helper.c | 457 ++++++++++ librpc/ndr/ndr_spoolss_buf.c | 1615 +++++++++++++++++++++++++++++++++ librpc/ndr/ndr_spoolss_buf.h | 84 ++ librpc/ndr/ndr_string.c | 1109 +++++++++++++++++++++++ librpc/ndr/ndr_svcctl.c | 52 ++ librpc/ndr/ndr_svcctl.h | 24 + librpc/ndr/ndr_table.c | 182 ++++ librpc/ndr/ndr_table.h | 37 + librpc/ndr/ndr_witness.c | 110 +++ librpc/ndr/ndr_witness.h | 23 + librpc/ndr/ndr_wmi.h | 24 + librpc/ndr/ndr_xattr.c | 148 +++ librpc/ndr/ndr_xattr.h | 37 + librpc/ndr/util.c | 36 + librpc/ndr/uuid.c | 258 ++++++ 69 files changed, 15417 insertions(+) create mode 100644 librpc/ndr/libndr.h create mode 100644 librpc/ndr/ndr.c create mode 100644 librpc/ndr/ndr_ODJ.c create mode 100644 librpc/ndr/ndr_ODJ.h create mode 100644 librpc/ndr/ndr_auth.c create mode 100644 librpc/ndr/ndr_auth.h create mode 100644 librpc/ndr/ndr_backupkey.c create mode 100644 librpc/ndr/ndr_backupkey.h create mode 100644 librpc/ndr/ndr_basic.c create mode 100644 librpc/ndr/ndr_bkupblobs.c create mode 100644 librpc/ndr/ndr_cab.c create mode 100644 librpc/ndr/ndr_cab.h create mode 100644 librpc/ndr/ndr_claims.c create mode 100644 librpc/ndr/ndr_claims.h create mode 100644 librpc/ndr/ndr_compression.c create mode 100644 librpc/ndr/ndr_compression.h create mode 100644 librpc/ndr/ndr_dcerpc.c create mode 100644 librpc/ndr/ndr_dcerpc.h create mode 100644 librpc/ndr/ndr_dns.c create mode 100644 librpc/ndr/ndr_dns.h create mode 100644 librpc/ndr/ndr_dns_utils.c create mode 100644 librpc/ndr/ndr_dns_utils.h create mode 100644 librpc/ndr/ndr_dnsp.c create mode 100644 librpc/ndr/ndr_dnsp.h create mode 100644 librpc/ndr/ndr_dnsserver.c create mode 100644 librpc/ndr/ndr_dnsserver.h create mode 100644 librpc/ndr/ndr_drsblobs.c create mode 100644 librpc/ndr/ndr_drsblobs.h create mode 100644 librpc/ndr/ndr_drsuapi.c create mode 100644 librpc/ndr/ndr_drsuapi.h create mode 100644 librpc/ndr/ndr_frsrpc.c create mode 100644 librpc/ndr/ndr_frsrpc.h create mode 100644 librpc/ndr/ndr_ioctl.c create mode 100644 librpc/ndr/ndr_krb5pac.c create mode 100644 librpc/ndr/ndr_krb5pac.h create mode 100644 librpc/ndr/ndr_misc.c create mode 100644 librpc/ndr/ndr_nbt.c create mode 100644 librpc/ndr/ndr_nbt.h create mode 100644 librpc/ndr/ndr_negoex.c create mode 100644 librpc/ndr/ndr_negoex.h create mode 100644 librpc/ndr/ndr_netlogon.c create mode 100644 librpc/ndr/ndr_netlogon.h create mode 100644 librpc/ndr/ndr_ntlmssp.c create mode 100644 librpc/ndr/ndr_ntlmssp.h create mode 100644 librpc/ndr/ndr_ntprinting.c create mode 100644 librpc/ndr/ndr_ntprinting.h create mode 100644 librpc/ndr/ndr_orpc.c create mode 100644 librpc/ndr/ndr_preg.c create mode 100644 librpc/ndr/ndr_preg.h create mode 100644 librpc/ndr/ndr_private.h create mode 100644 librpc/ndr/ndr_rap.c create mode 100644 librpc/ndr/ndr_rap.h create mode 100644 librpc/ndr/ndr_schannel.c create mode 100644 librpc/ndr/ndr_schannel.h create mode 100644 librpc/ndr/ndr_sec_helper.c create mode 100644 librpc/ndr/ndr_spoolss_buf.c create mode 100644 librpc/ndr/ndr_spoolss_buf.h create mode 100644 librpc/ndr/ndr_string.c create mode 100644 librpc/ndr/ndr_svcctl.c create mode 100644 librpc/ndr/ndr_svcctl.h create mode 100644 librpc/ndr/ndr_table.c create mode 100644 librpc/ndr/ndr_table.h create mode 100644 librpc/ndr/ndr_witness.c create mode 100644 librpc/ndr/ndr_witness.h create mode 100644 librpc/ndr/ndr_wmi.h create mode 100644 librpc/ndr/ndr_xattr.c create mode 100644 librpc/ndr/ndr_xattr.h create mode 100644 librpc/ndr/util.c create mode 100644 librpc/ndr/uuid.c (limited to 'librpc/ndr') diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h new file mode 100644 index 0000000..03d1aea --- /dev/null +++ b/librpc/ndr/libndr.h @@ -0,0 +1,918 @@ +/* + 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 . +*/ + +/* This is a public header file that is installed as part of Samba. + * If you remove any functions or change their signature, update + * the so version number. */ + +#ifndef __LIBNDR_H__ +#define __LIBNDR_H__ + +#include +#include "../lib/util/discard.h" /* for discard_const */ +#include "../lib/util/data_blob.h" +#include "../lib/util/time.h" +#include "../lib/util/charset/charset.h" + +/* + this provides definitions for the libcli/rpc/ MSRPC library +*/ + + +/* + We store the token mapping in an array that is resized as necessary. +*/ +struct ndr_token; + +struct ndr_token_list { + struct ndr_token *tokens; + uint32_t count; +}; + +struct ndr_compression_state; + +#define LIBNDR_STATIC_ASSERT(msg, cond) \ + typedef char static_assert_##msg[(cond) ? 1 : -1] + +/* + * If you’re considering changing the size of this type, see also + * $scalar_alignment in pidl/lib/Parse/Pidl/NDR.pm. + */ +typedef enum { + LIBNDR_FLAG_BIGENDIAN = 1U << 0, + LIBNDR_FLAG_NOALIGN = 1U << 1, + + LIBNDR_FLAG_STR_ASCII = 1U << 2, + LIBNDR_FLAG_STR_LEN4 = 1U << 3, + LIBNDR_FLAG_STR_SIZE4 = 1U << 4, + LIBNDR_FLAG_STR_NOTERM = 1U << 5, + LIBNDR_FLAG_STR_NULLTERM = 1U << 6, + LIBNDR_FLAG_STR_SIZE2 = 1U << 7, + LIBNDR_FLAG_STR_BYTESIZE = 1U << 8, + LIBNDR_FLAG_STR_NO_EMBEDDED_NUL = 1U << 9, + LIBNDR_FLAG_STR_CONFORMANT = 1U << 10, + LIBNDR_FLAG_STR_CHARLEN = 1U << 11, + LIBNDR_FLAG_STR_UTF8 = 1U << 12, + LIBNDR_FLAG_STR_RAW8 = 1U << 13, + + /* + * Mark an element as SECRET, it won't be printed via + * ndr_print* unless NDR_PRINT_SECRETS is specified. + */ + LIBNDR_FLAG_IS_SECRET = 1U << 14, + + /* Disable string token compression */ + LIBNDR_FLAG_NO_COMPRESSION = 1U << 15, + + /* + * don't debug NDR_ERR_BUFSIZE failures, + * as the available buffer might be incomplete. + * + * return NDR_ERR_INCOMPLETE_BUFFER instead. + */ + LIBNDR_FLAG_INCOMPLETE_BUFFER = 1U << 16, + + /* + * This lets ndr_pull_subcontext_end() return + * NDR_ERR_UNREAD_BYTES. + */ + LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES = 1U << 17, + + /* set if relative pointers should *not* be marshalled in reverse order */ + LIBNDR_FLAG_NO_RELATIVE_REVERSE = 1U << 18, + + /* set if relative pointers are marshalled in reverse order */ + LIBNDR_FLAG_RELATIVE_REVERSE = 1U << 19, + + LIBNDR_FLAG_REF_ALLOC = 1U << 20, + LIBNDR_FLAG_REMAINING = 1U << 21, + LIBNDR_FLAG_ALIGN2 = 1U << 22, + LIBNDR_FLAG_ALIGN4 = 1U << 23, + LIBNDR_FLAG_ALIGN8 = 1U << 24, + + LIBNDR_PRINT_ARRAY_HEX = 1U << 25, + LIBNDR_PRINT_SET_VALUES = 1U << 26, + + /* used to force a section of IDL to be little-endian */ + LIBNDR_FLAG_LITTLE_ENDIAN = 1U << 27, + + /* used to check if alignment padding is zero */ + LIBNDR_FLAG_PAD_CHECK = 1U << 28, + + LIBNDR_FLAG_NDR64 = 1U << 29, + + /* set if an object uuid will be present */ + LIBNDR_FLAG_OBJECT_PRESENT = 1U << 30, + + /* set to avoid recursion in ndr_size_*() calculation */ + LIBNDR_FLAG_NO_NDR_SIZE = 1U << 31, + + /* + * present to keep the size of this enumeration 64 bits until we need a + * 33rd flag. + */ + LIBNDR_FLAG_0x100000000 = UINT64_C(1) << 32, +} libndr_flags; +LIBNDR_STATIC_ASSERT(libndr_flags_are_64_bit, sizeof (libndr_flags) == 8); +#define PRI_LIBNDR_FLAGS PRIx64 +#define PRI_LIBNDR_FLAGS_DECIMAL PRIu64 + +/* +* If you’re considering changing the size of this type, see also +* $scalar_alignment in pidl/lib/Parse/Pidl/NDR.pm. +*/ +typedef enum { + /* + flags passed to control parse flow + These are deliberately in a different range to the NDR_IN/NDR_OUT + flags to catch mixups + */ + NDR_SCALARS = 0x100, + NDR_BUFFERS = 0x200, + + /* + flags passed to ndr_print_*() and ndr pull/push for functions + These are deliberately in a different range to the + NDR_SCALARS/NDR_BUFFERS flags to catch mixups + */ + NDR_IN = 0x10, + NDR_OUT = 0x20, + NDR_BOTH = 0x30, + NDR_SET_VALUES = 0x40, +} ndr_flags_type; +LIBNDR_STATIC_ASSERT(ndr_flags_are_32_bit, sizeof (ndr_flags_type) == 4); +#define PRI_NDR_FLAGS_TYPE PRIx32 + +#undef LIBNDR_STATIC_ASSERT + +/* 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 { + libndr_flags flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t data_size; + uint32_t offset; + + uint32_t relative_highest_offset; + uint32_t relative_base_offset; + uint32_t relative_rap_convert; + 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; + + struct ndr_compression_state *cstate; + + TALLOC_CTX *current_mem_ctx; + + /* this is used to ensure we generate unique reference IDs + between request and reply */ + uint32_t ptr_count; + uint32_t recursion_depth; + /* + * The global maximum depth for recursion. When set it overrides the + * value supplied by the max_recursion idl attribute. This is needed + * for fuzzing as ASAN uses a low threshold for stack depth to check + * for stack overflow. + */ + uint32_t global_max_recursion; +}; + +/* structure passed to functions that generate NDR formatted data */ +struct ndr_push { + libndr_flags flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t alloc_size; + uint32_t offset; + bool fixed_buf_size; + + uint32_t relative_base_offset; + uint32_t relative_end_offset; + struct ndr_token_list relative_base_list; + + struct ndr_token_list switch_list; + struct ndr_token_list relative_list; + struct ndr_token_list relative_begin_list; + struct ndr_token_list nbt_string_list; + struct ndr_token_list dns_string_list; + struct ndr_token_list full_ptr_list; + + struct ndr_compression_state *cstate; + + /* this is used to ensure we generate unique reference IDs */ + uint32_t ptr_count; +}; + +/* structure passed to functions that print IDL structures */ +struct ndr_print { + libndr_flags 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; + bool no_newline; + bool print_secrets; +}; + +#define LIBNDR_STRING_FLAGS (0U | \ + LIBNDR_FLAG_STR_ASCII | \ + LIBNDR_FLAG_STR_LEN4 | \ + LIBNDR_FLAG_STR_SIZE4 | \ + LIBNDR_FLAG_STR_NOTERM | \ + LIBNDR_FLAG_STR_NULLTERM | \ + LIBNDR_FLAG_STR_SIZE2 | \ + LIBNDR_FLAG_STR_BYTESIZE | \ + LIBNDR_FLAG_STR_NO_EMBEDDED_NUL | \ + LIBNDR_FLAG_STR_CONFORMANT | \ + LIBNDR_FLAG_STR_CHARLEN | \ + LIBNDR_FLAG_STR_UTF8 | \ + LIBNDR_FLAG_STR_RAW8 | \ + 0) + +#define LIBNDR_ENCODING_FLAGS (0U | \ + LIBNDR_FLAG_STR_ASCII | \ + LIBNDR_FLAG_STR_UTF8 | \ + LIBNDR_FLAG_STR_RAW8 | \ + 0) + +#define LIBNDR_ALIGN_FLAGS ( 0 | \ + LIBNDR_FLAG_NOALIGN | \ + LIBNDR_FLAG_REMAINING | \ + LIBNDR_FLAG_ALIGN2 | \ + LIBNDR_FLAG_ALIGN4 | \ + LIBNDR_FLAG_ALIGN8 | \ + 0) + +/* useful macro for debugging */ +#define NDR_PRINT_DEBUG(type, p) (void)ndr_print_debug(1, (ndr_print_fn_t)ndr_print_ ##type, #p, p, __location__, __func__) +#define NDR_PRINT_DEBUGC(dbgc_class, type, p) ndr_print_debugc(dbgc_class, (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) + +/** + * @brief Prints NDR structure. + * + * Like NDR_PRINT_DEBUG, but takes a debug level parameter. + * + * @param[in] l The debug level. + * @param[in] type ndr_print_#type is the function that will be called. + * @param[in] p Pointer to the struct. + * + * @code + * NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info); + * @endcode + * + * @return void. + */ +#define NDR_PRINT_DEBUG_LEVEL(l, type, p) \ + (void) ( CHECK_DEBUGLVL(l) \ + && ndr_print_debug(l, (ndr_print_fn_t)ndr_print_ ##type, #p, p, __location__, __func__) ) + +/* 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_HIDE_SECRET(ndr) \ + (unlikely(((ndr)->flags & LIBNDR_FLAG_IS_SECRET) && !(ndr)->print_secrets)) + +#define NDR_BE(ndr) (unlikely(((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_IPV6ADDRESS, + NDR_ERR_INVALID_POINTER, + NDR_ERR_UNREAD_BYTES, + NDR_ERR_NDR64, + NDR_ERR_FLAGS, + NDR_ERR_INCOMPLETE_BUFFER, + NDR_ERR_MAX_RECURSION_EXCEEDED, + NDR_ERR_UNDERFLOW +}; + +#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) + +/* + * Values here are chosen to be distinct from but recognisable as the + * values in ntifs.h and claims.idl + */ +enum ndr_compression_alg { + NDR_COMPRESSION_NONE = 0, /* 0x00 in ntifs.h */ + NDR_COMPRESSION_XPRESS_LZNT1 = 102, /* MS-XCA 0x02 in ntifs.h + * (Unimplemented) + */ + NDR_COMPRESSION_XPRESS_RAW = 103, /* MS-XCA 0x03 in ntifs.h + * (implemented in + * lib/compression but + * not connected to libndr) + */ + NDR_COMPRESSION_XPRESS_HUFF_RAW = 104, /* MS-XCA 0x04 in ntifs.h */ + NDR_COMPRESSION_MSZIP_CAB = 201, + NDR_COMPRESSION_MSZIP = 202, + NDR_COMPRESSION_XPRESS = 203, + NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2 = 204, /* Unimplemented */ + NDR_COMPRESSION_INVALID = 255, +}; + +#define NDR_PULL_CHECK_FLAGS(ndr, ndr_flags) do { \ + if (unlikely((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS))) { \ + return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid pull struct ndr_flags 0x%"PRI_NDR_FLAGS_TYPE, ndr_flags); \ + } \ +} while (0) + +#define NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags) do { \ + if ((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS)) \ + return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid push struct ndr_flags 0x%"PRI_NDR_FLAGS_TYPE, ndr_flags); \ +} while (0) + +#define NDR_PULL_CHECK_FN_FLAGS(ndr, flags) do { \ + if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) { \ + return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid fn pull flags 0x%"PRI_NDR_FLAGS_TYPE, flags); \ + } \ +} while (0) + +#define NDR_PUSH_CHECK_FN_FLAGS(ndr, flags) do { \ + if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) \ + return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid fn push flags 0x%"PRI_NDR_FLAGS_TYPE, flags); \ +} while (0) + +#define NDR_PULL_NEED_BYTES(ndr, n) do { \ + if (unlikely(\ + (n) > ndr->data_size || \ + ndr->offset + (n) > ndr->data_size || \ + ndr->offset + (n) < ndr->offset)) { \ + if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \ + uint32_t _available = ndr->data_size - ndr->offset; \ + uint32_t _missing = n - _available; \ + ndr->relative_highest_offset = _missing; \ + } \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %zu (%s)", (size_t)n, __location__); \ + } \ +} 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 (unlikely(!(ndr->flags & LIBNDR_FLAG_NOALIGN))) { \ + if (unlikely(ndr->flags & LIBNDR_FLAG_PAD_CHECK)) { \ + ndr_check_padding(ndr, n); \ + } \ + if(unlikely( \ + ((ndr->offset + (n-1)) & (~(n-1))) < ndr->offset)) {\ + return ndr_pull_error( \ + ndr, \ + NDR_ERR_BUFSIZE, \ + "Pull align (overflow) %zu", (size_t)n); \ + } \ + ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ + } \ + if (unlikely(ndr->offset > ndr->data_size)) { \ + if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \ + uint32_t _missing = ndr->offset - ndr->data_size; \ + ndr->relative_highest_offset = _missing; \ + } \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %zu", (size_t)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 (likely(!(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) + +#define NDR_RECURSION_CHECK(ndr, d) do { \ + uint32_t _ndr_min_ = (d); \ + if (ndr->global_max_recursion && ndr->global_max_recursion < (d)) { \ + _ndr_min_ = ndr->global_max_recursion; \ + } \ + ndr->recursion_depth++; \ + if (unlikely(ndr->recursion_depth > _ndr_min_)) { \ + return ndr_pull_error( \ + ndr, \ + NDR_ERR_MAX_RECURSION_EXCEEDED, \ + "Depth of recursion exceeds (%u)", \ + (unsigned) d); \ + } \ +} while (0) + +#define NDR_RECURSION_UNWIND(ndr) do { \ + if (unlikely(ndr->recursion_depth == 0)) { \ + return ndr_pull_error( \ + ndr, \ + NDR_ERR_UNDERFLOW, \ + "ndr_pull.recursion_depth is 0"); \ + } \ + ndr->recursion_depth--; \ +} 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 (unlikely(!NDR_ERR_CODE_IS_SUCCESS(_status))) { \ + return _status; \ + } \ +} while (0) + +/* if the call fails then free the ndr pointer */ +#define NDR_CHECK_FREE(call) do { \ + enum ndr_err_code _status; \ + _status = call; \ + if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(_status))) { \ + talloc_free(ndr); \ + 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 == 0) || (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 (unlikely(!(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 (unlikely(!(s))) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %zu * %s failed: %s\n", (size_t)n, # s, __location__); \ +} while (0) + + +#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \ + (s) = talloc_array(ndr, uint8_t, size); \ + if (unlikely(!(s))) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %zu failed: %s\n", (size_t)size, __location__); \ +} while (0) + +#define NDR_PUSH_ALLOC(ndr, s) do { \ + (s) = talloc_ptrtype(ndr, (s)); \ + if (unlikely(!(s))) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %s failed: %s\n", # s, __location__); \ +} while (0) + +#define NDR_ZERO_STRUCT(x) ndr_zero_memory(&(x), sizeof(x)) +#define NDR_ZERO_STRUCTP(x) do { \ + if ((x) != NULL) { \ + ndr_zero_memory((x), sizeof(*(x))); \ + } \ +} 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 *, ndr_flags_type ndr_flags, const void *); +typedef enum ndr_err_code (*ndr_pull_flags_fn_t)(struct ndr_pull *, ndr_flags_type 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 *, ndr_flags_type, const void *); + +#include "../libcli/util/error.h" +#include "librpc/gen_ndr/misc.h" + +extern const struct ndr_syntax_id ndr_transfer_syntax_ndr; +extern const struct ndr_syntax_id ndr_transfer_syntax_ndr64; +extern const struct ndr_syntax_id ndr_syntax_id_null; + +struct ndr_interface_call_pipe { + const char *name; + const char *chunk_struct_name; + size_t chunk_struct_size; + ndr_push_flags_fn_t ndr_push; + ndr_pull_flags_fn_t ndr_pull; + ndr_print_fn_t ndr_print; +}; + +struct ndr_interface_call_pipes { + uint32_t num_pipes; + const struct ndr_interface_call_pipe *pipes; +}; + +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; + struct ndr_interface_call_pipes in_pipes; + struct ndr_interface_call_pipes out_pipes; +}; + +struct ndr_interface_public_struct { + 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; +}; + +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; + uint32_t num_public_structs; + const struct ndr_interface_public_struct *public_structs; + 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; +}; + +struct sockaddr_storage; + +/********************************************************************* + Map an NT error code from a NDR error code. +*********************************************************************/ +NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err); +int ndr_map_error2errno(enum ndr_err_code ndr_err); +const char *ndr_map_error2string(enum ndr_err_code ndr_err); +#define ndr_errstr ndr_map_error2string + +/* FIXME: Use represent_as instead */ +struct dom_sid; +enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid); +enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid); +void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid); +enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid); +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, libndr_flags flags); +enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid); +enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid); +void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags); +void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid); +void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss); +void ndr_zero_memory(void *ptr, size_t len); +bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1, const struct ndr_syntax_id *i2); + +struct ndr_syntax_id_buf { char buf[39 /*GUID*/ + 3 /* "/0x" */ + 8]; }; +char *ndr_syntax_id_buf_string( + const struct ndr_syntax_id *id, struct ndr_syntax_id_buf *buf); +char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id); + +bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id); +enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn); +enum ndr_err_code ndr_push_struct_into_fixed_blob(DATA_BLOB *blob, + const void *p, + ndr_push_flags_fn_t fn); +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); +size_t ndr_size_struct(const void *p, libndr_flags flags, ndr_push_flags_fn_t push); +size_t ndr_size_union(const void *p, libndr_flags flags, uint32_t level, ndr_push_flags_fn_t push); +uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr); +void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset); +enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset); +enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p); +uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr); +void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset); +enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset); +enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p); +enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset); +enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p); +enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v); +size_t ndr_align_size(uint32_t offset, size_t n); +struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx); +enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob); +enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr); +enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size); +struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx); +DATA_BLOB ndr_push_blob(struct ndr_push *ndr); +enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size); +void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +bool ndr_print_debug(int level, ndr_print_fn_t fn, const char *name, void *ptr, const char *location, const char *function); +void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr); +void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr); +void ndr_print_function_debug(ndr_print_function_t fn, const char *name, ndr_flags_type flags, void *ptr); +char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr); +char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr); +char *ndr_print_function_string(TALLOC_CTX *mem_ctx, + ndr_print_function_t fn, const char *name, + ndr_flags_type flags, void *ptr); +void ndr_set_flags(libndr_flags *pflags, libndr_flags new_flags); +enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr, + enum ndr_err_code ndr_err, + const char *function, + const char *location, + const char *format, ...) PRINTF_ATTRIBUTE(5,6); +#define ndr_pull_error(ndr, ndr_err, ...) \ + _ndr_pull_error(ndr, \ + ndr_err, \ + __FUNCTION__, \ + __location__, \ + __VA_ARGS__) +enum ndr_err_code _ndr_push_error(struct ndr_push *ndr, + enum ndr_err_code ndr_err, + const char *function, + const char *location, + const char *format, ...) PRINTF_ATTRIBUTE(5,6); +#define ndr_push_error(ndr, ndr_err, ...) \ + _ndr_push_error(ndr, \ + ndr_err, \ + __FUNCTION__, \ + __location__, \ + __VA_ARGS__) +enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr, + struct ndr_pull **_subndr, + size_t header_size, + ssize_t size_is); +enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr, + struct ndr_pull *subndr, + size_t header_size, + ssize_t size_is); +enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr, + struct ndr_push **_subndr, + size_t header_size, + ssize_t size_is); +enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr, + struct ndr_push *subndr, + size_t header_size, + ssize_t size_is); +enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, + struct ndr_token_list *list, + const void *key, + uint32_t value); +enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list, const void *key, uint32_t *v, + int(*_cmp_fn)(const void*,const void*), bool erase); +enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list, const void *key, uint32_t *v); +enum ndr_err_code ndr_token_peek(struct ndr_token_list *list, const void *key, uint32_t *v); +enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p); +enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size); +enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size); +enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size); +enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size); +enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p); +enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length); +enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length); +enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length); +enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length); +enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t count); +enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t count); +enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val); +enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val); +enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val); +/* retrieve a switch value (for push) and remove it from the list */ +enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr, + const void *p, + uint32_t *v); +/* retrieve a switch value and remove it from the list */ +uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p); +/* retrieve a switch value and remove it from the list */ +enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr, + const void *p, + uint32_t *v); +enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, ndr_pull_flags_fn_t fn); +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); +_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf, + size_t buflen, + void *p, + ndr_pull_flags_fn_t fn, + size_t *consumed); +enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob, + void *p, ndr_pull_flags_fn_t fn); +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); +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); + +/* from libndr_basic.h */ +#define NDR_SCALAR_PROTO(name, type) \ +enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, type v); \ +enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type *v); \ +void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, type v); + +#define NDR_SCALAR_PTR_PROTO(name, type) \ +enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const type *v); \ +enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type **v); \ +void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v); + +#define NDR_BUFFER_PROTO(name, type) \ +enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const type *v); \ +enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type *v); \ +void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v); + +NDR_SCALAR_PROTO(uint8, uint8_t) +NDR_SCALAR_PROTO(int8, int8_t) +NDR_SCALAR_PROTO(uint16, uint16_t) +NDR_SCALAR_PROTO(int16, int16_t) +NDR_SCALAR_PROTO(uint1632, uint16_t) +NDR_SCALAR_PROTO(uint32, uint32_t) +NDR_SCALAR_PROTO(uint3264, uint32_t) +NDR_SCALAR_PROTO(int32, int32_t) +NDR_SCALAR_PROTO(int3264, int32_t) +NDR_SCALAR_PROTO(udlong, uint64_t) +NDR_SCALAR_PROTO(udlongr, uint64_t) +NDR_SCALAR_PROTO(dlong, int64_t) +NDR_SCALAR_PROTO(hyper, uint64_t) +NDR_SCALAR_PROTO(int64, int64_t) +NDR_SCALAR_PROTO(pointer, void *) +NDR_SCALAR_PROTO(time_t, time_t) +NDR_SCALAR_PROTO(uid_t, uid_t) +NDR_SCALAR_PROTO(gid_t, gid_t) +NDR_SCALAR_PROTO(NTSTATUS, NTSTATUS) +NDR_SCALAR_PROTO(WERROR, WERROR) +NDR_SCALAR_PROTO(HRESULT, HRESULT) +NDR_SCALAR_PROTO(NTTIME, NTTIME) +NDR_SCALAR_PROTO(NTTIME_1sec, NTTIME) +NDR_SCALAR_PROTO(NTTIME_hyper, NTTIME) +NDR_SCALAR_PROTO(DATA_BLOB, DATA_BLOB) +NDR_SCALAR_PROTO(ipv4address, const char *) +NDR_SCALAR_PROTO(ipv6address, const char *) +NDR_SCALAR_PROTO(string, const char *) +NDR_SCALAR_PROTO(u16string, const unsigned char *) +NDR_SCALAR_PROTO(double, double) + +enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct policy_handle *r); +enum ndr_err_code ndr_push_policy_handle(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct policy_handle *r); +void ndr_print_policy_handle(struct ndr_print *ndr, const char *name, const struct policy_handle *r); +bool ndr_policy_handle_empty(const struct policy_handle *h); +#define is_valid_policy_hnd(hnd) (!ndr_policy_handle_empty(hnd)) +bool ndr_policy_handle_equal(const struct policy_handle *hnd1, + const struct policy_handle *hnd2); + +void ndr_check_padding(struct ndr_pull *ndr, size_t n); +enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v); +enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v); +enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n); +enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *data, uint32_t n); +enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size); +enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size); +enum ndr_err_code ndr_push_union_align(struct ndr_push *ndr, size_t size); +enum ndr_err_code ndr_pull_union_align(struct ndr_pull *ndr, size_t size); +enum ndr_err_code ndr_push_trailer_align(struct ndr_push *ndr, size_t size); +enum ndr_err_code ndr_pull_trailer_align(struct ndr_pull *ndr, size_t size); +enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n); +enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n); +enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, const uint8_t *data, uint32_t n); +enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p); +enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr); +void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type); +void ndr_print_null(struct ndr_print *ndr); +void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type, const char *val, uint32_t value); +void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value); +void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value); +void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p); +void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type); +void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level); +void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, const uint8_t *data, uint32_t count); +uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, ndr_flags_type flags); + +/* strings */ +uint32_t ndr_charset_length(const void *var, charset_t chset); +size_t ndr_string_array_size(struct ndr_push *ndr, const char *s); +uint32_t ndr_size_string(int ret, const char * const* string, ndr_flags_type flags); +enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char ***_a); +enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char **a); +void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a); +size_t ndr_size_string_array(const char **a, uint32_t count, libndr_flags flags); +uint32_t ndr_string_length(const void *_var, uint32_t element_size); +enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size); +enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset); +enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset); +enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset); +enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset); + +/* GUIDs */ +bool GUID_equal(const struct GUID *u1, const struct GUID *u2); +struct GUID_ndr_buf { uint8_t buf[16]; }; +NTSTATUS GUID_to_ndr_buf(const struct GUID *guid, struct GUID_ndr_buf *buf); +NTSTATUS GUID_to_ndr_blob(const struct GUID *guid, TALLOC_CTX *mem_ctx, DATA_BLOB *b); +NTSTATUS GUID_from_ndr_blob(const DATA_BLOB *b, struct GUID *guid); +NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid); +NTSTATUS GUID_from_string(const char *s, struct GUID *guid); +struct GUID GUID_zero(void); +bool GUID_all_zero(const struct GUID *u); +int GUID_compare(const struct GUID *u1, const struct GUID *u2); +char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid); +char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid); +char *GUID_hexstring(TALLOC_CTX *mem_ctx, const struct GUID *guid); +struct GUID GUID_random(void); + +/* Format is "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" */ + /* 32 chars + 4 ' ' + \0 + 2 for adding {} */ +struct GUID_txt_buf { char buf[39]; }; +_PUBLIC_ char* GUID_buf_string(const struct GUID *guid, + struct GUID_txt_buf *dst); + +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *v); +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v); +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v); +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v); +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint8_t v); +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint16(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v); +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint32(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v); +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v); + +_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b); + +_PUBLIC_ enum ndr_err_code ndr_push_timespec(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct timespec *t); +_PUBLIC_ enum ndr_err_code ndr_pull_timespec(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct timespec *t); +_PUBLIC_ void ndr_print_timespec(struct ndr_print *ndr, const char *name, + const struct timespec *t); + +_PUBLIC_ enum ndr_err_code ndr_push_timeval(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct timeval *t); +_PUBLIC_ enum ndr_err_code ndr_pull_timeval(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct timeval *t); +_PUBLIC_ void ndr_print_timeval(struct ndr_print *ndr, const char *name, + const struct timeval *t); + +_PUBLIC_ void ndr_print_libndr_flags(struct ndr_print *ndr, const char *name, + libndr_flags flags); + + +#endif /* __LIBNDR_H__ */ diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c new file mode 100644 index 0000000..1478faa --- /dev/null +++ b/librpc/ndr/ndr.c @@ -0,0 +1,2040 @@ +/* + Unix SMB/CIFS implementation. + + libndr interface + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Jelmer Vernooij 2005-2008 + + 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 . +*/ + +/* + 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" +#include "librpc/ndr/libndr.h" +#include "librpc/ndr/ndr_private.h" +#include "../lib/util/dlinklist.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_PARSE + +#define NDR_BASE_MARSHALL_SIZE 1024 + +/* + * This value is arbitrary, but designed to reduce the memory a client + * can allocate and the work the client can force in processing a + * malicious packet. + * + * In an ideal world this would be controlled by range() restrictions + * on array sizes and careful IDL construction to avoid arbitrary + * linked lists, but this is a backstop for now. + */ +#define NDR_TOKEN_MAX_LIST_SIZE 65535 + +size_t ndr_token_max_list_size(void) { + return NDR_TOKEN_MAX_LIST_SIZE; +}; + +/* this guid indicates NDR encoding in a protocol tower */ +const struct ndr_syntax_id ndr_transfer_syntax_ndr = { + { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} }, + 2 +}; + +const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = { + { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} }, + 1 +}; + +const struct ndr_syntax_id ndr_syntax_id_null = { + { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } }, + 0 +}; + +/* + 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; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob) +{ + enum ndr_err_code ndr_err; + DATA_BLOB b; + uint32_t append = 0; + bool ok; + + if (blob->length == 0) { + return NDR_ERR_SUCCESS; + } + + ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append); + if (ndr_err == NDR_ERR_TOKEN) { + append = 0; + ndr_err = NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_err); + + if (ndr->data_size == 0) { + ndr->data = NULL; + append = UINT32_MAX; + } + + if (append == UINT32_MAX) { + /* + * append == UINT32_MAX means that + * ndr->data is either NULL or a valid + * talloc child of ndr, which means + * we can use data_blob_append() without + * data_blob_talloc() of the existing callers data + */ + b = data_blob_const(ndr->data, ndr->data_size); + } else { + b = data_blob_talloc(ndr, ndr->data, ndr->data_size); + if (b.data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + } + + ok = data_blob_append(ndr, &b, blob->data, blob->length); + if (!ok) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + + ndr->data = b.data; + ndr->data_size = b.length; + + return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX); +} + +_PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr) +{ + uint32_t skip = 0; + uint32_t append = 0; + enum ndr_err_code ndr_err; + + if (ndr->relative_base_offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_highest_offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_list.count != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_base_list.count != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + + /* + * we need to keep up to 7 bytes + * in order to get the alignment right. + */ + skip = ndr->offset & 0xFFFFFFF8; + + if (skip == 0) { + return NDR_ERR_SUCCESS; + } + + ndr->offset -= skip; + ndr->data_size -= skip; + + ndr_err = ndr_token_peek(&ndr->array_size_list, ndr, &append); + if (ndr_err == NDR_ERR_TOKEN) { + /* + * here we assume, that ndr->data is not a + * talloc child of ndr. + */ + ndr->data += skip; + return NDR_ERR_SUCCESS; + } + + memmove(ndr->data, ndr->data + skip, ndr->data_size); + + ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size); + if (ndr->data_size != 0 && ndr->data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + + return NDR_ERR_SUCCESS; +} + +/* + advance by 'size' bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size) +{ + NDR_PULL_NEED_BYTES(ndr, size); + ndr->offset += 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 %"PRIu32" failed", + ofs); + } + return NDR_ERR_SUCCESS; +} + +/* 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) { + talloc_free(ndr); + 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 %"PRIu32, + size); + } + + if (ndr->fixed_buf_size) { + if (ndr->alloc_size >= size) { + return NDR_ERR_SUCCESS; + } + return ndr_push_error(ndr, + NDR_ERR_BUFSIZE, + "Overflow of fixed buffer in " + "push_expand to %"PRIu32, + size); + } + + if (ndr->alloc_size > size) { + return NDR_ERR_SUCCESS; + } + + ndr->alloc_size += NDR_BASE_MARSHALL_SIZE; + if (size == UINT32_MAX) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand"); + } + 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 %"PRIu32, + ndr->alloc_size); + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...) +{ + va_list ap; + char *s = NULL; + uint32_t i; + int ret; + int dbgc_class; + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return; + } + + dbgc_class = *(int *)ndr->private_data; + + if (ndr->no_newline) { + DEBUGADDC(dbgc_class, 1,("%s", s)); + free(s); + return; + } + + for (i=0;idepth;i++) { + DEBUGADDC(dbgc_class, 1,(" ")); + } + + DEBUGADDC(dbgc_class, 1,("%s\n", s)); + free(s); +} + +_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) +{ + va_list ap; + char *s = NULL; + uint32_t i; + int ret; + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return; + } + + if (ndr->no_newline) { + DEBUGADD(1,("%s", s)); + free(s); + return; + } + + for (i=0;idepth;i++) { + DEBUGADD(1,(" ")); + } + + DEBUGADD(1,("%s\n", s)); + free(s); +} + +_PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...) +{ + va_list ap; + uint32_t i; + + if (!ndr->no_newline) { + for (i=0;idepth;i++) { + printf(" "); + } + } + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + if (!ndr->no_newline) { + printf("\n"); + } +} + +_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) +{ + va_list ap; + uint32_t i; + + if (!ndr->no_newline) { + for (i=0;idepth;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); + if (!ndr->no_newline) { + ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data, + "\n"); + } +} + +/* + a useful helper function for printing idl structures via DEBUGC() +*/ +_PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr) +{ + struct ndr_print *ndr; + + DEBUGC(dbgc_class, 1,(" ")); + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->private_data = &dbgc_class; + ndr->print = ndr_print_debugc_helper; + ndr->depth = 1; + ndr->flags = 0; +#ifdef DEBUG_PASSWORD + if (CHECK_DEBUGLVL(100)) { + ndr->print_secrets = true; + } +#endif + + fn(ndr, name, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl structures via DEBUG() +*/ +_PUBLIC_ bool ndr_print_debug(int level, + ndr_print_fn_t fn, + const char *name, + void *ptr, + const char *location, + const char *function) +{ + struct ndr_print *ndr; + + DEBUGLF(level, (" "), location, function); + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return false; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; +#ifdef DEBUG_PASSWORD + if (CHECK_DEBUGLVL(100)) { + ndr->print_secrets = true; + } +#endif + + fn(ndr, name, ptr); + talloc_free(ndr); + return true; +} + +/* + 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; + + DEBUG(1,(" ")); + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; +#ifdef DEBUG_PASSWORD + if (CHECK_DEBUGLVL(100)) { + ndr->print_secrets = true; + } +#endif + + 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, ndr_flags_type flags, void *ptr) +{ + struct ndr_print *ndr; + + DEBUG(1,(" ")); + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; +#ifdef DEBUG_PASSWORD + if (CHECK_DEBUGLVL(100)) { + ndr->print_secrets = true; + } +#endif + + 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, + ndr_flags_type 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(libndr_flags *pflags, libndr_flags new_flags) +{ + /* the big/little endian flags are inter-dependent */ + if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) { + (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN; + (*pflags) &= ~LIBNDR_FLAG_NDR64; + } + if (new_flags & LIBNDR_FLAG_BIGENDIAN) { + (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN; + (*pflags) &= ~LIBNDR_FLAG_NDR64; + } + if (new_flags & LIBNDR_ALIGN_FLAGS) { + /* Ensure we only have the passed-in + align flag set in the new_flags, + remove any old align flag. */ + (*pflags) &= ~LIBNDR_ALIGN_FLAGS; + } + if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) { + (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE; + } + (*pflags) |= new_flags; +} + +/* + 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 *function, + const char *location, + const char *format, ...) +{ + char *s=NULL; + va_list ap; + int ret; + + if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { + switch (ndr_err) { + case NDR_ERR_BUFSIZE: + return NDR_ERR_INCOMPLETE_BUFFER; + default: + break; + } + } + + va_start(ap, format); + ret = vasprintf(&s, format, ap); + va_end(ap); + + if (ret == -1) { + return NDR_ERR_ALLOC; + } + + D_WARNING("%s: ndr_pull_error(%s): %s at %s\n", + function, + ndr_map_error2string(ndr_err), + s, + location); + + 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 *function, + const char *location, + const char *format, ...) +{ + 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; + } + + D_WARNING("%s: ndr_push_error(%s): %s at %s\n", + function, + ndr_map_error2string(ndr_err), + s, + location); + + 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; + bool force_le = false; + bool force_be = false; + + switch (header_size) { + case 0: { + uint32_t content_size = ndr->data_size - ndr->offset; + if (size_is >= 0) { + content_size = size_is; + } + r_content_size = content_size; + break; + } + + case 2: { + uint16_t content_size; + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size)); + if (size_is >= 0 && size_is != content_size) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%04zx) mismatch content_size %"PRIu16" (0x%04"PRIx16")", + size_is, size_is, + content_size, + content_size); + } + r_content_size = content_size; + break; + } + + case 4: { + uint32_t content_size; + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size)); + if (size_is >= 0 && size_is != content_size) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%08zx) mismatch content_size %"PRIu32" (0x%08"PRIx32")", + size_is, size_is, + content_size, + content_size); + } + r_content_size = content_size; + break; + } + case 0xFFFFFC01: { + /* + * Common Type Header for the Serialization Stream + * See [MS-RPCE] 2.2.6 Type Serialization Version 1 + */ + uint8_t version; + uint8_t drep; + uint16_t hdrlen; + uint32_t filler; + uint32_t content_size; + uint32_t reserved; + + /* version */ + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version)); + + if (version != 1) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, + "Bad subcontext (PULL) Common Type Header version %"PRIu8" != 1", + version); + } + + /* + * 0x10 little endian + * 0x00 big endian + */ + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep)); + if (drep == 0x10) { + force_le = true; + } else if (drep == 0x00) { + force_be = true; + } else { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, + "Bad subcontext (PULL) Common Type Header invalid drep 0x%02"PRIX8, + drep); + } + + /* length of the "Private Header for Constructed Type" */ + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen)); + if (hdrlen != 8) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, + "Bad subcontext (PULL) Common Type Header length %"PRIu16" != 8", + hdrlen); + } + + /* filler should be ignored */ + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler)); + + /* + * Private Header for Constructed Type + */ + /* length - will be updated later */ + 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(%zd) mismatch content_size %"PRIu32, + size_is, content_size); + } + /* the content size must be a multiple of 8 */ + if ((content_size % 8) != 0) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, + "Bad subcontext (PULL) size_is(%zd) not padded to 8 content_size %"PRIu32, + size_is, content_size); + } + r_content_size = content_size; + + /* reserved */ + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved)); + break; + } + case 0xFFFFFFFF: + /* + * a shallow copy like subcontext + * useful for DCERPC pipe chunks. + */ + 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; + subndr->offset = ndr->offset; + subndr->data_size = ndr->data_size; + + *_subndr = subndr; + return NDR_ERR_SUCCESS; + + default: + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %zu", + header_size); + } + + NDR_PULL_NEED_BYTES(ndr, r_content_size); + + subndr = talloc_zero(ndr, struct ndr_pull); + NDR_ERR_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; + subndr->current_mem_ctx = ndr->current_mem_ctx; + + subndr->data = ndr->data + ndr->offset; + subndr->offset = 0; + subndr->data_size = r_content_size; + + if (force_le) { + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN); + } else if (force_be) { + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN); + } + + *_subndr = subndr; + return NDR_ERR_SUCCESS; +} + +_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; + uint32_t highest_ofs; + + if (header_size == 0xFFFFFFFF) { + advance = subndr->offset - ndr->offset; + } else if (size_is >= 0) { + advance = size_is; + } else if (header_size > 0) { + advance = subndr->data_size; + } else { + advance = subndr->offset; + } + + if (subndr->offset > ndr->relative_highest_offset) { + highest_ofs = subndr->offset; + } else { + highest_ofs = subndr->relative_highest_offset; + } + if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) { + /* + * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified + */ + highest_ofs = advance; + } + if (highest_ofs < advance) { + return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES, + "not all bytes consumed ofs[%"PRIu32"] advance[%"PRIu32"]", + highest_ofs, advance); + } + + 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 & ~LIBNDR_FLAG_NDR64; + + if (size_is > 0) { + enum ndr_err_code status; + + status = ndr_push_zero(subndr, size_is); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + talloc_free(subndr); + return status; + } + subndr->offset = 0; + subndr->relative_end_offset = size_is; + } + + *_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) +{ + ssize_t padding_len; + + if (size_is >= 0) { + padding_len = size_is - subndr->offset; + if (padding_len < 0) { + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %"PRIu32" is larger than size_is(%zd)", + subndr->offset, size_is); + } + subndr->offset = 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_uint3264(ndr, NDR_SCALARS, subndr->offset)); + break; + + case 0xFFFFFC01: + /* + * Common Type Header for the Serialization Stream + * See [MS-RPCE] 2.2.6 Type Serialization Version 1 + */ + padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset; + if (padding_len > 0) { + NDR_CHECK(ndr_push_zero(subndr, padding_len)); + } + + /* version */ + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1)); + + /* + * 0x10 little endian + * 0x00 big endian + */ + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10)); + + /* length of the "Private Header for Constructed Type" */ + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8)); + + /* filler */ + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC)); + + /* + * Private Header for Constructed Type + */ + /* length - will be updated later */ + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset)); + + /* reserved */ + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + break; + + default: + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %zu", + header_size); + } + + NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset)); + return NDR_ERR_SUCCESS; +} + + +struct ndr_token { + const void *key; + uint32_t value; +}; + +/* + 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) +{ + if (list->tokens == NULL) { + list->tokens = talloc_array(mem_ctx, struct ndr_token, 10); + if (list->tokens == NULL) { + NDR_ERR_HAVE_NO_MEMORY(list->tokens); + } + } else { + struct ndr_token *new_tokens = NULL; + uint32_t alloc_count = talloc_array_length(list->tokens); + + /* + * Check every time we have not allocated too many + * tokens. This ensures developer sanity when + * debugging the boundary condition + */ + if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) { + return NDR_ERR_RANGE; + } + if (list->count == alloc_count) { + uint32_t new_alloc; + /* + * Double the list, until we start in chunks + * of 1000 + */ + uint32_t increment = MIN(list->count, 1000); + new_alloc = alloc_count + increment; + if (new_alloc < alloc_count) { + return NDR_ERR_RANGE; + } + new_tokens = talloc_realloc(mem_ctx, list->tokens, + struct ndr_token, new_alloc); + NDR_ERR_HAVE_NO_MEMORY(new_tokens); + list->tokens = new_tokens; + } + } + list->tokens[list->count].key = key; + list->tokens[list->count].value = value; + list->count++; + 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 erase) +{ + struct ndr_token *tokens = list->tokens; + unsigned i; + if (_cmp_fn) { + for (i = list->count - 1; i < list->count; i--) { + if (_cmp_fn(tokens[i].key, key) == 0) { + goto found; + } + } + } else { + for (i = list->count - 1; i < list->count; i--) { + if (tokens[i].key == key) { + goto found; + } + } + } + return NDR_ERR_TOKEN; +found: + *v = tokens[i].value; + if (erase) { + if (i != list->count - 1) { + tokens[i] = tokens[list->count - 1]; + } + list->count--; + } + 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_ enum ndr_err_code ndr_token_peek(struct ndr_token_list *list, + const void *key, uint32_t *v) +{ + return ndr_token_retrieve_cmp_fn(list, key, v, NULL, false); +} + +/* + 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) +{ + enum ndr_err_code ret; + uint32_t size; + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size)); + ret = ndr_token_store(ndr, &ndr->array_size_list, p, size); + if (ret == NDR_ERR_RANGE) { + return ndr_pull_error(ndr, ret, + "More than %d NDR tokens stored for array_size", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + get the stored array size field +*/ +_PUBLIC_ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size) +{ + return ndr_token_peek(&ndr->array_size_list, p, size); +} + +/* + get and remove from the stored list the stored array size field +*/ +_PUBLIC_ enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size) +{ + return ndr_token_retrieve(&ndr->array_size_list, p, size); +} + +/* + * check the stored array size field and remove from the stored list + * (the array_size NDR token list). We try to remove when possible to + * avoid the list growing towards the bounds check + */ +_PUBLIC_ enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size) +{ + uint32_t stored; + NDR_CHECK(ndr_steal_array_size(ndr, p, &stored)); + 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; +} + +/* + * check the stored array size field (leaving it on the array_size + * token list) + */ +_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size) +{ + uint32_t stored; + NDR_CHECK(ndr_get_array_size(ndr, p, &stored)); + if (stored != size) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array size - got %"PRIu32" expected %"PRIu32"\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) +{ + enum ndr_err_code ret; + uint32_t length, offset; + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset)); + if (offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "non-zero array offset %"PRIu32"\n", offset); + } + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length)); + ret = ndr_token_store(ndr, &ndr->array_length_list, p, length); + if (ret == NDR_ERR_RANGE) { + return ndr_pull_error(ndr, ret, + "More than %d NDR tokens stored for array_length_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + get the stored array length field +*/ +_PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length) +{ + return ndr_token_peek(&ndr->array_length_list, p, length); +} + +/* + * check the stored array length field and remove from the stored list + * (the array_size NDR token list). We try to remove when possible to + * avoid the list growing towards the bounds check + */ +_PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length) +{ + return ndr_token_retrieve(&ndr->array_length_list, p, length); +} +/* + check the stored array length field, removing it from the list +*/ +_PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length) +{ + uint32_t stored; + NDR_CHECK(ndr_steal_array_length(ndr, p, &stored)); + if (stored != length) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array length: got %"PRIu32" expected %"PRIu32"\n", + stored, length); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t count) +{ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + int64_t tmp = 0 - (int64_t)count; + uint64_t ncount = tmp; + + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount)); + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t count) +{ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + int64_t tmp = 0 - (int64_t)count; + uint64_t ncount1 = tmp; + uint64_t ncount2; + + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2)); + if (ncount1 == ncount2) { + return NDR_ERR_SUCCESS; + } + + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad pipe trailer[%"PRIu64" should be %"PRIu64"] size was %"PRIu32"\"", + ncount2, + ncount1, + count); + } + + 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) +{ + enum ndr_err_code ret = + ndr_token_store(ndr, &ndr->switch_list, p, val); + if (ret == NDR_ERR_RANGE) { + return ndr_push_error(ndr, ret, + "More than %d NDR tokens stored for switch_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val) +{ + + enum ndr_err_code ret = + ndr_token_store(ndr, &ndr->switch_list, p, val); + if (ret == NDR_ERR_RANGE) { + return ndr_pull_error(ndr, ret, + "More than %d NDR tokens stored for switch_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +_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 (for push) and remove it from the list */ +_PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr, + const void *p, + uint32_t *v) +{ + return ndr_token_retrieve(&ndr->switch_list, p, v); +} + +/* retrieve a switch value and remove it from the list */ +_PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p) +{ + enum ndr_err_code status; + uint32_t v; + + status = ndr_token_retrieve(&ndr->switch_list, p, &v); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + return 0; + } + + return v; +} + +/* retrieve a switch value and remove it from the list */ +_PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr, + const void *p, + uint32_t *v) +{ + return ndr_token_retrieve(&ndr->switch_list, p, v); +} + +/* + 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_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + talloc_free(ndr); + 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; + uint32_t highest_ofs; + ndr = ndr_pull_init_blob(blob, mem_ctx); + NDR_ERR_HAVE_NO_MEMORY(ndr); + NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + if (ndr->offset > ndr->relative_highest_offset) { + highest_ofs = ndr->offset; + } else { + highest_ofs = ndr->relative_highest_offset; + } + if (highest_ofs < ndr->data_size) { + enum ndr_err_code ret; + ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES, + "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]", + highest_ofs, ndr->data_size); + talloc_free(ndr); + return ret; + } + talloc_free(ndr); + return NDR_ERR_SUCCESS; +} + +/* + * pull a struct from a blob using NDR + * + * This only works for structures with NO allocated memory, like + * objectSID and GUID. This helps because we parse these a lot. + */ +_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf, + size_t buflen, + void *p, + ndr_pull_flags_fn_t fn, + size_t *consumed) +{ + /* + * We init this structure on the stack here, to avoid a + * talloc() as otherwise this call to the fn() is assured not + * to be doing any allocation, eg SIDs and GUIDs. + * + * This allows us to keep the safety of the PIDL-generated + * code without the talloc() overhead. + */ + struct ndr_pull ndr = { + .data = discard_const_p(uint8_t, buf), + .data_size = buflen, + .current_mem_ctx = (void *)-1, + }; + + NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); + *consumed = MAX(ndr.offset, ndr.relative_highest_offset); + + return NDR_ERR_SUCCESS; +} + +/* + pull a struct from a blob using NDR - failing if all bytes are not consumed + + This only works for structures with NO allocated memory, like + objectSID and GUID. This helps because we parse these a lot. +*/ +_PUBLIC_ enum ndr_err_code +ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob, + void *p, + ndr_pull_flags_fn_t fn) +{ + size_t consumed; + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_struct_blob_noalloc(blob->data, + blob->length, + p, + fn, + &consumed); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_err; + } + + if (consumed < blob->length) { + D_WARNING("not all bytes consumed ofs[%zu] size[%zu]", + consumed, + blob->length); + return NDR_ERR_UNREAD_BYTES; + } + + return NDR_ERR_SUCCESS; +} + +/* + pull a union from a blob using NDR, given the union discriminator +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + void *p, + uint32_t level, ndr_pull_flags_fn_t fn) +{ + struct ndr_pull *ndr; + ndr = ndr_pull_init_blob(blob, mem_ctx); + NDR_ERR_HAVE_NO_MEMORY(ndr); + NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level)); + NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + talloc_free(ndr); + return NDR_ERR_SUCCESS; +} + +/* + pull a union from a blob using NDR, given the union discriminator, + failing if all bytes are not consumed +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + void *p, + uint32_t level, ndr_pull_flags_fn_t fn) +{ + struct ndr_pull *ndr; + uint32_t highest_ofs; + ndr = ndr_pull_init_blob(blob, mem_ctx); + NDR_ERR_HAVE_NO_MEMORY(ndr); + NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level)); + NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p)); + if (ndr->offset > ndr->relative_highest_offset) { + highest_ofs = ndr->offset; + } else { + highest_ofs = ndr->relative_highest_offset; + } + if (highest_ofs < ndr->data_size) { + enum ndr_err_code ret; + ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES, + "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]", + highest_ofs, ndr->data_size); + talloc_free(ndr); + return ret; + } + talloc_free(ndr); + 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_FREE(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 struct into a provided blob using NDR. + + We error because we want to have the performance issue (extra + talloc() calls) show up as an error, not just slower code. This is + used for things like GUIDs, which we expect to be a fixed size, and + SIDs that we can pre-calculate the size for. +*/ +_PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob( + DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn) +{ + struct ndr_push ndr = { + .data = blob->data, + .alloc_size = blob->length, + .fixed_buf_size = true + }; + + NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); + + if (ndr.offset != blob->length) { + return ndr_push_error(&ndr, NDR_ERR_BUFSIZE, + "buffer was either too large or small " + "ofs[%"PRIu32"] size[%zu]", + ndr.offset, blob->length); + } + + 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_FREE(ndr_push_set_switch_value(ndr, p, level)); + NDR_CHECK_FREE(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, libndr_flags 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; + + /* Avoid following a NULL pointer */ + if (p == NULL) { + 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, libndr_flags 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; + + /* Avoid following a NULL pointer */ + if (p == NULL) { + 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) +{ + enum ndr_err_code ret; + ndr->relative_base_offset = offset; + ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset); + if (ret == NDR_ERR_RANGE) { + return ndr_push_error(ndr, ret, + "More than %d NDR tokens stored for relative_base_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + 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) +{ + enum ndr_err_code ret; + if (p == NULL) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_align(ndr, 4)); + ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset); + if (ret == NDR_ERR_RANGE) { + return ndr_push_error(ndr, ret, + "More than %d NDR tokens stored for relative_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + NDR_CHECK(ret); + return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF); +} + +/* + push a short relative object - stage1 + this is called during SCALARS processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p) +{ + enum ndr_err_code ret; + if (p == NULL) { + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0)); + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_align(ndr, 2)); + ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset); + if (ret == NDR_ERR_RANGE) { + return ndr_push_error(ndr, ret, + "More than %d NDR tokens stored for relative_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + NDR_CHECK(ret); + return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF); +} +/* + push a relative object - stage2 + this is called during buffers processing +*/ +static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p) +{ + uint32_t save_offset; + uint32_t ptr_offset = 0xFFFFFFFF; + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + save_offset = ndr->offset; + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset)); + if (ptr_offset > ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")", + 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(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")", + save_offset, ndr->relative_base_offset); + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset)); + ndr->offset = save_offset; + return NDR_ERR_SUCCESS; +} +/* + push a short relative object - stage2 + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p) +{ + uint32_t save_offset; + uint32_t ptr_offset = 0xFFFF; + uint32_t relative_offset; + size_t pad; + size_t align = 1; + + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + + if (ndr->offset < ndr->relative_base_offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")", + ndr->offset, ndr->relative_base_offset); + } + + relative_offset = ndr->offset - ndr->relative_base_offset; + + if (ndr->flags & LIBNDR_FLAG_NOALIGN) { + align = 1; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + align = 2; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + align = 4; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + align = 8; + } + + pad = ndr_align_size(relative_offset, align); + if (pad != 0) { + NDR_CHECK(ndr_push_zero(ndr, pad)); + } + + relative_offset = ndr->offset - ndr->relative_base_offset; + if (relative_offset > UINT16_MAX) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 relative_offset(%"PRIu32") > UINT16_MAX", + relative_offset); + } + + save_offset = ndr->offset; + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset)); + if (ptr_offset > ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_short_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")", + ptr_offset, ndr->offset); + } + ndr->offset = ptr_offset; + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset)); + ndr->offset = save_offset; + return NDR_ERR_SUCCESS; +} + +/* + push a relative object - stage2 start + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p) +{ + enum ndr_err_code ret; + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { + uint32_t relative_offset; + size_t pad; + size_t align = 1; + + if (ndr->offset < ndr->relative_base_offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2_start ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")", + ndr->offset, ndr->relative_base_offset); + } + + relative_offset = ndr->offset - ndr->relative_base_offset; + + if (ndr->flags & LIBNDR_FLAG_NOALIGN) { + align = 1; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + align = 2; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + align = 4; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + align = 8; + } + + pad = ndr_align_size(relative_offset, align); + if (pad) { + NDR_CHECK(ndr_push_zero(ndr, pad)); + } + + return ndr_push_relative_ptr2(ndr, p); + } + if (ndr->relative_end_offset == -1) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %"PRIu32, + ndr->relative_end_offset); + } + ret = ndr_token_store(ndr, + &ndr->relative_begin_list, + p, + ndr->offset); + if (ret == NDR_ERR_RANGE) { + return ndr_push_error(ndr, ret, + "More than %d NDR tokens stored for array_size", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + push a relative object - stage2 end + this is called during buffers processing +*/ +_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p) +{ + uint32_t begin_offset = 0xFFFFFFFF; + ssize_t len; + uint32_t correct_offset = 0; + uint32_t align = 1; + uint32_t pad = 0; + + if (p == NULL) { + return NDR_ERR_SUCCESS; + } + + if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { + return NDR_ERR_SUCCESS; + } + + if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) { + /* better say more than calculation a too small buffer */ + NDR_PUSH_ALIGN(ndr, 8); + return NDR_ERR_SUCCESS; + } + + if (ndr->relative_end_offset < ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %"PRIu32" < offset %"PRIu32, + ndr->relative_end_offset, ndr->offset); + } + + NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset)); + + /* we have marshalled a buffer, see how long it was */ + len = ndr->offset - begin_offset; + + if (len < 0) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "offset %"PRIu32" - begin_offset %"PRIu32" < 0", + ndr->offset, begin_offset); + } + + if (ndr->relative_end_offset < len) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %"PRIu32" < len %zd", + ndr->offset, len); + } + + /* the reversed offset is at the end of the main buffer */ + correct_offset = ndr->relative_end_offset - len; + + if (ndr->flags & LIBNDR_FLAG_NOALIGN) { + align = 1; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + align = 2; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + align = 4; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + align = 8; + } + + pad = ndr_align_size(correct_offset, align); + if (pad) { + correct_offset += pad; + correct_offset -= align; + } + + if (correct_offset < begin_offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end: " + "correct_offset %"PRIu32" < begin_offset %"PRIu32, + correct_offset, begin_offset); + } + + if (len > 0) { + uint32_t clear_size = correct_offset - begin_offset; + + clear_size = MIN(clear_size, len); + + /* now move the marshalled buffer to the end of the main buffer */ + memmove(ndr->data + correct_offset, ndr->data + begin_offset, len); + + if (clear_size) { + /* and wipe out old buffer within the main buffer */ + memset(ndr->data + begin_offset, '\0', clear_size); + } + } + + /* and set the end offset for the next buffer */ + ndr->relative_end_offset = correct_offset; + + /* finally write the offset to the main buffer */ + ndr->offset = correct_offset; + NDR_CHECK(ndr_push_relative_ptr2(ndr, p)); + + /* restore to where we were in the main buffer */ + ndr->offset = begin_offset; + + return NDR_ERR_SUCCESS; +} + +/* + get the current base for relative pointers for the pull +*/ +_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) +{ + enum ndr_err_code ret; + ndr->relative_base_offset = offset; + ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset); + if (ret == NDR_ERR_RANGE) { + return ndr_pull_error(ndr, ret, + "More than %d NDR tokens stored for relative_base_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + 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) +{ + enum ndr_err_code ret; + 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(%"PRIu32") > ndr->data_size(%"PRIu32")", + rel_offset, ndr->data_size); + } + ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset); + if (ret == NDR_ERR_RANGE) { + return ndr_pull_error(ndr, ret, + "More than %d NDR tokens stored for relative_list", + NDR_TOKEN_MAX_LIST_SIZE); + } + return ret; +} + +/* + 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); +} + +static const struct { + enum ndr_err_code err; + const char *string; +} ndr_err_code_strings[] = { + { NDR_ERR_SUCCESS, "Success" }, + { NDR_ERR_ARRAY_SIZE, "Bad Array Size" }, + { NDR_ERR_BAD_SWITCH, "Bad Switch" }, + { NDR_ERR_OFFSET, "Offset Error" }, + { NDR_ERR_RELATIVE, "Relative Pointer Error" }, + { NDR_ERR_CHARCNV, "Character Conversion Error" }, + { NDR_ERR_LENGTH, "Length Error" }, + { NDR_ERR_SUBCONTEXT, "Subcontext Error" }, + { NDR_ERR_COMPRESSION, "Compression Error" }, + { NDR_ERR_STRING, "String Error" }, + { NDR_ERR_VALIDATE, "Validate Error" }, + { NDR_ERR_BUFSIZE, "Buffer Size Error" }, + { NDR_ERR_ALLOC, "Allocation Error" }, + { NDR_ERR_RANGE, "Range Error" }, + { NDR_ERR_TOKEN, "Token Error" }, + { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" }, + { NDR_ERR_INVALID_POINTER, "Invalid Pointer" }, + { NDR_ERR_UNREAD_BYTES, "Unread Bytes" }, + { NDR_ERR_NDR64, "NDR64 assertion error" }, + { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" }, + { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" }, + { NDR_ERR_UNDERFLOW, "Underflow" }, + { 0, NULL } +}; + +_PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err) +{ + int i; + for (i = 0; ndr_err_code_strings[i].string != NULL; i++) { + if (ndr_err_code_strings[i].err == ndr_err) + return ndr_err_code_strings[i].string; + } + return "Unknown error"; +} diff --git a/librpc/ndr/ndr_ODJ.c b/librpc/ndr/ndr_ODJ.c new file mode 100644 index 0000000..86630b8 --- /dev/null +++ b/librpc/ndr/ndr_ODJ.c @@ -0,0 +1,65 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ODJ structures + + Copyright (C) Guenther Deschner 2021 + + 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_ODJ.h" +#include "../librpc/ndr/ndr_ODJ.h" + +uint32_t odj_switch_level_from_guid(const struct GUID *r) +{ + struct { + uint16_t level; + const char *guid; + } levels[] = { + { + .level = 1, + .guid = ODJ_GUID_JOIN_PROVIDER + },{ + .level = 2, + .guid = ODJ_GUID_JOIN_PROVIDER2 + },{ + .level = 3, + .guid = ODJ_GUID_JOIN_PROVIDER3 + },{ + .level = 4, + .guid = ODJ_GUID_CERT_PROVIDER + },{ + .level = 5, + .guid = ODJ_GUID_POLICY_PROVIDER + } + }; + int i; + + for (i = 0; i < ARRAY_SIZE(levels); i++) { + struct GUID guid; + NTSTATUS status; + + status = GUID_from_string(levels[i].guid, &guid); + if (!NT_STATUS_IS_OK(status)) { + return 0; + } + if (GUID_equal(&guid, r)) { + return levels[i].level; + } + } + + return 0; +} diff --git a/librpc/ndr/ndr_ODJ.h b/librpc/ndr/ndr_ODJ.h new file mode 100644 index 0000000..f57f2d7 --- /dev/null +++ b/librpc/ndr/ndr_ODJ.h @@ -0,0 +1,22 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ODJ structures + + Copyright (C) Guenther Deschner 2021 + + 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 . +*/ + +uint32_t odj_switch_level_from_guid(const struct GUID *r); diff --git a/librpc/ndr/ndr_auth.c b/librpc/ndr/ndr_auth.c new file mode 100644 index 0000000..0600586 --- /dev/null +++ b/librpc/ndr/ndr_auth.c @@ -0,0 +1,44 @@ +/* + Unix SMB/CIFS implementation. + + Helper routines for marshalling the internal 'auth.idl' + + Copyright (C) Andrew Bartlett 2011 + + 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 . +*/ + +#include "includes.h" +#include "librpc/ndr/ndr_auth.h" +#include "librpc/ndr/libndr.h" + +_PUBLIC_ void ndr_print_cli_credentials(struct ndr_print *ndr, const char *name, struct cli_credentials *v) +{ + ndr->print(ndr, "%-25s: NULL", name); +} + +/* + cli_credentials does not have a network representation, just pull/push a NULL pointer +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_cli_credentials(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v) +{ + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_cli_credentials(struct ndr_push *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v) +{ + return ndr_push_pointer(ndr, ndr_flags, NULL); +} + + diff --git a/librpc/ndr/ndr_auth.h b/librpc/ndr/ndr_auth.h new file mode 100644 index 0000000..9cc4ec2 --- /dev/null +++ b/librpc/ndr/ndr_auth.h @@ -0,0 +1,32 @@ +/* + Unix SMB/CIFS implementation. + + Helper routines for marshalling the internal 'auth.idl' + + Copyright (C) Andrew Bartlett 2011 + + 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 . +*/ + +/* + cli_credentials does not have a network representation, just pull/push a NULL pointer +*/ + +#include "librpc/gen_ndr/ndr_auth.h" + +struct cli_credentials; +_PUBLIC_ enum ndr_err_code ndr_pull_cli_credentials(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v); +_PUBLIC_ enum ndr_err_code ndr_push_cli_credentials(struct ndr_push *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v); + +_PUBLIC_ void ndr_print_cli_credentials(struct ndr_print *ndr, const char *name, struct cli_credentials *v); diff --git a/librpc/ndr/ndr_backupkey.c b/librpc/ndr/ndr_backupkey.c new file mode 100644 index 0000000..9ce1abb --- /dev/null +++ b/librpc/ndr/ndr_backupkey.c @@ -0,0 +1,222 @@ +/* + Unix SMB/CIFS implementation. + + routines for top backup key protocol marshalling/unmarshalling + + Copyright (C) Matthieu Patou 2010 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_backupkey.h" +#include "librpc/gen_ndr/ndr_security.h" + +static uint32_t backupkeyguid_to_uint(const struct GUID *guid) +{ + struct GUID tmp; + NTSTATUS status; + bool match; + + status = GUID_from_string(BACKUPKEY_RESTORE_GUID, &tmp); + if (NT_STATUS_IS_OK(status)) { + match = GUID_equal(guid, &tmp); + if (match) { + return BACKUPKEY_RESTORE_GUID_INTEGER; + } + } + + status = GUID_from_string(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, &tmp); + if (NT_STATUS_IS_OK(status)) { + match = GUID_equal(guid, &tmp); + if (match) { + return BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER; + } + } + + return BACKUPKEY_INVALID_GUID_INTEGER; +} + +_PUBLIC_ void ndr_print_bkrp_BackupKey(struct ndr_print *ndr, const char *name, ndr_flags_type flags, const struct bkrp_BackupKey *r) +{ + ndr_print_struct(ndr, name, "bkrp_BackupKey"); + if (r == NULL) { ndr_print_null(ndr); return; } + ndr->depth++; + if (flags & NDR_SET_VALUES) { + ndr->flags |= LIBNDR_PRINT_SET_VALUES; + } + if (flags & NDR_IN) { + union bkrp_data_in_blob inblob = { + .empty._empty_ = '\0', + }; + DATA_BLOB blob; + uint32_t level; + enum ndr_err_code ndr_err; + + ndr_print_struct(ndr, "in", "bkrp_BackupKey"); + ndr->depth++; + ndr_print_ptr(ndr, "guidActionAgent", r->in.guidActionAgent); + ndr->depth++; + ndr_print_GUID(ndr, "guidActionAgent", r->in.guidActionAgent); + ndr->depth--; + + level = backupkeyguid_to_uint(r->in.guidActionAgent); + ndr_err = ndr_print_set_switch_value(ndr, &inblob, level); + if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(ndr_err))) { \ + DEBUG(0,("ERROR: ndr_print_bkrp_BackupKey ndr_print_set_switch_value failed: %d\n", ndr_err)); + return; + } + blob.data = r->in.data_in; + blob.length = r->in.data_in_len; + ndr_err = ndr_pull_union_blob(&blob, ndr, &inblob, level, + (ndr_pull_flags_fn_t)ndr_pull_bkrp_data_in_blob); + + ndr_print_ptr(ndr, "data_in", r->in.data_in); + ndr->depth++; + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + ndr_print_bkrp_data_in_blob(ndr, "data_in", &inblob); + } else { + ndr_print_array_uint8(ndr, "data_in", r->in.data_in, r->in.data_in_len); + } + ndr->depth--; + + ndr_print_uint32(ndr, "data_in_len", r->in.data_in_len); + ndr_print_uint32(ndr, "param", r->in.param); + ndr->depth--; + } + if (flags & NDR_OUT) { + ndr_print_struct(ndr, "out", "bkrp_BackupKey"); + ndr->depth++; + ndr_print_ptr(ndr, "data_out", r->out.data_out); + ndr->depth++; + ndr_print_ptr(ndr, "data_out", *r->out.data_out); + ndr->depth++; + + if (*r->out.data_out) { + ndr_print_array_uint8(ndr, "data_out", *r->out.data_out, *r->out.data_out_len); + } + ndr->depth--; + ndr->depth--; + ndr_print_ptr(ndr, "data_out_len", r->out.data_out_len); + ndr->depth++; + ndr_print_uint32(ndr, "data_out_len", *r->out.data_out_len); + ndr->depth--; + ndr_print_WERROR(ndr, "result", r->out.result); + ndr->depth--; + } + ndr->depth--; +} + +/* We have manual push/pull because we didn't manage to do the alignment + * purely in PIDL as the padding is sized so that the whole access_check_v3 + * struct size is a multiple of 8 (as specified in 2.2.2.3 of ms-bkrp.pdf) + */ +_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v2 *r) +{ + if (ndr_flags & NDR_SCALARS) { + size_t ofs; + size_t pad; + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00000001)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nonce_len)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len)); + NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->sid)); + /* We articially increment the offset of 20 bytes (size of hash + * coming after the pad) so that ndr_align can determine easily + * the correct pad size to make the whole struct 8 bytes aligned + */ + ofs = ndr->offset + 20; + pad = ndr_align_size(ofs, 8); + NDR_CHECK(ndr_push_zero(ndr, pad)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 20)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v2 *r) +{ + if (ndr_flags & NDR_SCALARS) { + size_t ofs; + size_t pad; + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonce_len)); + NDR_PULL_ALLOC_N(ndr, r->nonce, r->nonce_len); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len)); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->sid)); + ofs = ndr->offset + 20; + pad = ndr_align_size(ofs, 8); + NDR_CHECK(ndr_pull_advance(ndr, pad)); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 20)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +/* We have manual push/pull because we didn't manage to do the alignment + * purely in PIDL as the padding is sized so that the whole access_check_v3 + * struct size is a multiple of 16 (as specified in 2.2.2.4 of ms-bkrp.pdf) + */ +_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v3(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v3 *r) +{ + if (ndr_flags & NDR_SCALARS) { + size_t ofs; + size_t pad; + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00000001)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nonce_len)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len)); + NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->sid)); + /* We articially increment the offset of 64 bytes (size of hash + * coming after the pad) so that ndr_align can determine easily + * the correct pad size to make the whole struct 16 bytes aligned + */ + ofs = ndr->offset + 64; + pad = ndr_align_size(ofs, 16); + NDR_CHECK(ndr_push_zero(ndr, pad)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 64)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v3(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v3 *r) +{ + if (ndr_flags & NDR_SCALARS) { + size_t ofs; + size_t pad; + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonce_len)); + NDR_PULL_ALLOC_N(ndr, r->nonce, r->nonce_len); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len)); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->sid)); + ofs = ndr->offset + 64; + pad = ndr_align_size(ofs, 16); + NDR_CHECK(ndr_pull_advance(ndr, pad)); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 64)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_backupkey.h b/librpc/ndr/ndr_backupkey.h new file mode 100644 index 0000000..20386d2 --- /dev/null +++ b/librpc/ndr/ndr_backupkey.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + + routines for top backup key protocol marshalling/unmarshalling + + Copyright (C) Matthieu Patou 2010 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v2 *r); +_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v2 *r); diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c new file mode 100644 index 0000000..5fd1573 --- /dev/null +++ b/librpc/ndr/ndr_basic.c @@ -0,0 +1,1596 @@ +/* + 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 . +*/ + +#include "replace.h" +#include "system/network.h" +#include "librpc/ndr/libndr.h" +#include "lib/util/util_net.h" +#include "lib/util/debug.h" +#include "lib/util/util.h" +#include "lib/util/bytearray.h" + +#define NDR_PULL_U16(ndr, ofs) \ + (NDR_BE(ndr) ? PULL_BE_U16(ndr->data,ofs) : PULL_LE_U16(ndr->data,ofs)) + +#define NDR_PULL_U32(ndr, ofs) \ + (NDR_BE(ndr) ? PULL_BE_U32(ndr->data,ofs) : PULL_LE_U32(ndr->data,ofs)) + +#define NDR_PULL_I32(ndr, ofs) \ + (int32_t)(NDR_BE(ndr) ? PULL_BE_U32(ndr->data,ofs) : PULL_LE_U32(ndr->data,ofs)) + +#define NDR_PULL_I64(ndr, ofs) \ + (NDR_BE(ndr) ? PULL_BE_I64((ndr)->data, ofs) : PULL_LE_I64((ndr)->data, ofs)) + +#define NDR_PUSH_U16(ndr, ofs, v) \ + do { \ + if (NDR_BE(ndr)) { \ + PUSH_BE_U16(ndr->data, ofs, v); \ + } else { \ + PUSH_LE_U16(ndr->data, ofs, v); \ + } \ + } while (0) + +#define NDR_PUSH_U32(ndr, ofs, v) \ + do { \ + if (NDR_BE(ndr)) { \ + PUSH_BE_U32(ndr->data, ofs, v); \ + } else { \ + PUSH_LE_U32(ndr->data, ofs, v); \ + } \ + } while (0) + +#define NDR_PUSH_I32(ndr, ofs, v) \ + do { \ + if (NDR_BE(ndr)) { \ + PUSH_BE_U32(ndr->data, ofs, v); \ + } else { \ + PUSH_LE_U32(ndr->data, ofs, v); \ + } \ + } while (0) + +#define NDR_PUSH_I64(ndr, ofs, v) \ + do { \ + if (NDR_BE(ndr)) { \ + PUSH_BE_I64((ndr)->data, ofs, v); \ + } else { \ + PUSH_LE_I64((ndr)->data, ofs, v); \ + } \ + } while (0) + +static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len); + +/* + 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); + size_t i; + for (i=ndr->offset;idata[i] != 0) { + break; + } + } + if (ioffset;idata[i])); + } + DEBUG(0,("\n")); + } + +} + +/* + parse a int8_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int8_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_NEED_BYTES(ndr, 1); + *v = (int8_t)PULL_BE_U8(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, ndr_flags_type ndr_flags, uint8_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_NEED_BYTES(ndr, 1); + *v = PULL_BE_U8(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, ndr_flags_type ndr_flags, int16_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = (uint16_t)NDR_PULL_U16(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, ndr_flags_type ndr_flags, uint16_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = NDR_PULL_U16(ndr, ndr->offset); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + parse a uint1632_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) { + uint32_t v32 = 0; + enum ndr_err_code err = ndr_pull_uint32(ndr, ndr_flags, &v32); + *v = v32; + if (unlikely(v32 != *v)) { + DEBUG(0,(__location__ ": non-zero upper 16 bits 0x%08"PRIx32"\n", v32)); + return NDR_ERR_NDR64; + } + return err; + } + return ndr_pull_uint16(ndr, ndr_flags, v); +} + +/* + parse a int32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int32_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_PULL_I32(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, ndr_flags_type ndr_flags, uint32_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_PULL_U32(ndr, ndr->offset); + ndr->offset += 4; + return NDR_ERR_SUCCESS; +} + +/* + parse a arch dependent uint32/uint64 +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uint3264(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v) +{ + uint64_t v64 = 0; + enum ndr_err_code err; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (likely(!(ndr->flags & LIBNDR_FLAG_NDR64))) { + return ndr_pull_uint32(ndr, ndr_flags, v); + } + err = ndr_pull_hyper(ndr, ndr_flags, &v64); + if (!NDR_ERR_CODE_IS_SUCCESS(err)) { + return err; + } + *v = (uint32_t)v64; + if (unlikely(v64 != *v)) { + DEBUG(0,(__location__ ": non-zero upper 32 bits 0x%016"PRIx64"\n", + v64)); + return ndr_pull_error(ndr, NDR_ERR_NDR64, __location__ ": non-zero upper 32 bits 0x%016"PRIx64"\n", + v64); + } + return err; +} + +/* + parse a double +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_double(struct ndr_pull *ndr, ndr_flags_type ndr_flags, double *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 8); + NDR_PULL_NEED_BYTES(ndr, 8); + memcpy(v, ndr->data+ndr->offset, 8); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + parse a pointer referent identifier stored in 2 bytes +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v) +{ + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, v)); + if (*v != 0) { + ndr->ptr_count++; + } + *(v) -= ndr->relative_rap_convert; + return NDR_ERR_SUCCESS; +} + +/* + parse a pointer referent identifier +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v) +{ + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v)); + if (*v != 0) { + ndr->ptr_count++; + } + return NDR_ERR_SUCCESS; +} + +/* + parse a ref pointer referent identifier +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v) +{ + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v)); + /* ref pointers always point to data */ + *v = 1; + return NDR_ERR_SUCCESS; +} + +/* + parse a udlong +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint64_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = NDR_PULL_U32(ndr, ndr->offset); + *v |= (uint64_t)(NDR_PULL_U32(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, ndr_flags_type ndr_flags, uint64_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = ((uint64_t)NDR_PULL_U32(ndr, ndr->offset)) << 32; + *v |= NDR_PULL_U32(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, ndr_flags_type 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, ndr_flags_type ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 8); + if (NDR_BE(ndr)) { + return ndr_pull_udlongr(ndr, ndr_flags, v); + } + return ndr_pull_udlong(ndr, ndr_flags, v); +} + +/* + parse an int64 +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_int64(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int64_t *v) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_PULL_ALIGN(ndr, 8); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = NDR_PULL_I64(ndr, ndr->offset); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + parse a pointer +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, void* *v) +{ + uintptr_t h; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, NTSTATUS *status) +{ + uint32_t v; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type 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, ndr_flags_type ndr_flags, WERROR *status) +{ + uint32_t v; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = W_ERROR(v); + return NDR_ERR_SUCCESS; +} + +/* + pull a HRESULT +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_HRESULT(struct ndr_pull *ndr, ndr_flags_type ndr_flags, HRESULT *status) +{ + uint32_t v; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = HRES_ERROR(v); + return NDR_ERR_SUCCESS; +} + +/* + parse a uint8_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *v) +{ + return ndr_pull_uint8(ndr, ndr_flags, v); +} + +/* + parse a uint16_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v) +{ + return ndr_pull_uint16(ndr, ndr_flags, v); +} + +/* + parse a uint1632_t enum (uint32_t on NDR64) +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v) +{ + if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) { + uint32_t v32; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &v32)); + *v = v32; + if (v32 != *v) { + DEBUG(0,(__location__ ": non-zero upper 16 bits 0x%08"PRIx32"\n", v32)); + return NDR_ERR_NDR64; + } + return NDR_ERR_SUCCESS; + } + return ndr_pull_uint16(ndr, ndr_flags, v); +} + +/* + parse a uint32_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v) +{ + return ndr_pull_uint32(ndr, ndr_flags, v); +} + +/* + push a uint8_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint8_t v) +{ + return ndr_push_uint8(ndr, ndr_flags, v); +} + +/* + push a uint16_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint16(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v) +{ + return ndr_push_uint16(ndr, ndr_flags, v); +} + +/* + push a uint32_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint32(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v) +{ + return ndr_push_uint32(ndr, ndr_flags, v); +} + +/* + push a uint1632_t enum +*/ +_PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v) +{ + if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) { + return ndr_push_uint32(ndr, ndr_flags, v); + } + return ndr_push_uint16(ndr, ndr_flags, v); +} + +/* + push a WERROR +*/ +_PUBLIC_ enum ndr_err_code ndr_push_WERROR(struct ndr_push *ndr, ndr_flags_type 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)); +} + +/* + push a HRESULT +*/ +_PUBLIC_ enum ndr_err_code ndr_push_HRESULT(struct ndr_push *ndr, ndr_flags_type ndr_flags, HRESULT status) +{ + return ndr_push_uint32(ndr, NDR_SCALARS, HRES_ERROR_V(status)); +} + +_PUBLIC_ void ndr_print_HRESULT(struct ndr_print *ndr, const char *name, HRESULT r) +{ + ndr->print(ndr, "%-25s: %s", name, hresult_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, ndr_flags_type ndr_flags, uint8_t *data, uint32_t n) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, int8_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_NEED_BYTES(ndr, 1); + PUSH_BE_U8(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, ndr_flags_type ndr_flags, uint8_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_NEED_BYTES(ndr, 1); + PUSH_BE_U8(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, ndr_flags_type ndr_flags, int16_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_PUSH_U16(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, ndr_flags_type ndr_flags, uint16_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_PUSH_U16(ndr, ndr->offset, v); + ndr->offset += 2; + return NDR_ERR_SUCCESS; +} + +/* + push a uint1632 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v) +{ + if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) { + return ndr_push_uint32(ndr, ndr_flags, v); + } + return ndr_push_uint16(ndr, ndr_flags, v); +} + +/* + push a int32_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, ndr_flags_type ndr_flags, int32_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_PUSH_I32(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, ndr_flags_type ndr_flags, uint32_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_PUSH_U32(ndr, ndr->offset, v); + ndr->offset += 4; + return NDR_ERR_SUCCESS; +} + +/* + push a uint3264 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uint3264(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v) +{ + if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) { + return ndr_push_hyper(ndr, ndr_flags, v); + } + return ndr_push_uint32(ndr, ndr_flags, v); +} + +/* + push a udlong +*/ +_PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint64_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_PUSH_U32(ndr, ndr->offset, (v & 0xFFFFFFFF)); + NDR_PUSH_U32(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, ndr_flags_type ndr_flags, uint64_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_PUSH_U32(ndr, ndr->offset, (v>>32)); + NDR_PUSH_U32(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, ndr_flags_type 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, ndr_flags_type ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 8); + if (NDR_BE(ndr)) { + return ndr_push_udlongr(ndr, NDR_SCALARS, v); + } + return ndr_push_udlong(ndr, NDR_SCALARS, v); +} + +/* + push an int64 +*/ +_PUBLIC_ enum ndr_err_code ndr_push_int64(struct ndr_push *ndr, ndr_flags_type ndr_flags, int64_t v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 8); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_PUSH_I64(ndr, ndr->offset, v); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + push a double +*/ +_PUBLIC_ enum ndr_err_code ndr_push_double(struct ndr_push *ndr, ndr_flags_type ndr_flags, double v) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_PUSH_ALIGN(ndr, 8); + NDR_PUSH_NEED_BYTES(ndr, 8); + memcpy(ndr->data+ndr->offset, &v, 8); + ndr->offset += 8; + return NDR_ERR_SUCCESS; +} + +/* + push a pointer +*/ +_PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, ndr_flags_type ndr_flags, void* v) +{ + uintptr_t h = (intptr_t)v; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + 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) +{ + /* this is a nasty hack to make pidl work with NDR64 */ + if (size == 5) { + if (ndr->flags & LIBNDR_FLAG_NDR64) { + size = 8; + } else { + size = 4; + } + } else if (size == 3) { + if (ndr->flags & LIBNDR_FLAG_NDR64) { + size = 4; + } else { + size = 2; + } + } + NDR_PUSH_ALIGN(ndr, size); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size) +{ + /* this is a nasty hack to make pidl work with NDR64 */ + if (size == 5) { + if (ndr->flags & LIBNDR_FLAG_NDR64) { + size = 8; + } else { + size = 4; + } + } else if (size == 3) { + if (ndr->flags & LIBNDR_FLAG_NDR64) { + size = 4; + } else { + size = 2; + } + } + NDR_PULL_ALIGN(ndr, size); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_union_align(struct ndr_push *ndr, size_t size) +{ + /* MS-RPCE section 2.2.5.3.4.4 */ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + return ndr_push_align(ndr, size); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_union_align(struct ndr_pull *ndr, size_t size) +{ + /* MS-RPCE section 2.2.5.3.4.4 */ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + return ndr_pull_align(ndr, size); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_trailer_align(struct ndr_push *ndr, size_t size) +{ + /* MS-RPCE section 2.2.5.3.4.1 */ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + return ndr_push_align(ndr, size); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_trailer_align(struct ndr_pull *ndr, size_t size) +{ + /* MS-RPCE section 2.2.5.3.4.1 */ + if (ndr->flags & LIBNDR_FLAG_NDR64) { + return 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) +{ + if (unlikely(n == 0)) { + return NDR_ERR_SUCCESS; + } + if (unlikely(data == NULL)) { + return NDR_ERR_INVALID_POINTER; + } + 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, ndr_flags_type ndr_flags, const uint8_t *data, uint32_t n) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + return ndr_push_bytes(ndr, data, n); +} + +/* + 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_uint3264(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) +{ + enum ndr_err_code ret = NDR_ERR_SUCCESS; + uint32_t ptr = 0; + if (p) { + /* Check if the pointer already exists and has an id */ + ret = ndr_token_peek(&ndr->full_ptr_list, p, &ptr); + if (ret == NDR_ERR_TOKEN) { + ndr->ptr_count++; + ptr = ndr->ptr_count; + ret = ndr_token_store(ndr, &ndr->full_ptr_list, p, ptr); + if (ret != NDR_ERR_SUCCESS) { + return ret; + } + } else if (ret != NDR_ERR_SUCCESS) { + return ret; + } + } + return ndr_push_uint3264(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_uint3264(ndr, NDR_SCALARS, 0xAEF1AEF1); +} + + +/* + push a NTTIME +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTTIME t) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, NTTIME *t) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, t)); + return NDR_ERR_SUCCESS; +} + +/* + push a NTTIME_1sec +*/ +_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTTIME t) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, NTTIME *t) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, NTTIME *t) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type ndr_flags, NTTIME t) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + 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, ndr_flags_type 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, ndr_flags_type ndr_flags, time_t *t) +{ + uint32_t tt; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &tt)); + *t = tt; + return NDR_ERR_SUCCESS; +} + + +/* + push a uid_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_uid_t(struct ndr_push *ndr, ndr_flags_type ndr_flags, uid_t u) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)u); +} + +/* + pull a uid_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_uid_t(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uid_t *u) +{ + uint64_t uu = 0; + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &uu)); + *u = (uid_t)uu; + if (unlikely(uu != *u)) { + DEBUG(0,(__location__ ": uid_t pull doesn't fit 0x%016"PRIx64"\n", + uu)); + return NDR_ERR_NDR64; + } + return NDR_ERR_SUCCESS; +} + + +/* + push a gid_t +*/ +_PUBLIC_ enum ndr_err_code ndr_push_gid_t(struct ndr_push *ndr, ndr_flags_type ndr_flags, gid_t g) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)g); +} + +/* + pull a gid_t +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_gid_t(struct ndr_pull *ndr, ndr_flags_type ndr_flags, gid_t *g) +{ + uint64_t gg = 0; + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &gg)); + *g = (gid_t)gg; + if (unlikely(gg != *g)) { + DEBUG(0,(__location__ ": gid_t pull doesn't fit 0x%016"PRIx64"\n", + gg)); + return NDR_ERR_NDR64; + } + return NDR_ERR_SUCCESS; +} + + +/* + pull a ipv4address +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_ipv4address(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **address) +{ + uint32_t addr; + struct in_addr in; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &addr)); + in.s_addr = htonl(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, ndr_flags_type ndr_flags, const char *address) +{ + uint32_t addr; + if (!is_ipaddress_v4(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); +} + +/* + pull a ipv6address +*/ +#define IPV6_BYTES 16 +#define IPV6_ADDR_STR_LEN 39 +_PUBLIC_ enum ndr_err_code ndr_pull_ipv6address(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **address) +{ + uint8_t addr[IPV6_BYTES]; + char *addr_str = talloc_strdup(ndr->current_mem_ctx, ""); + int i; + NDR_ERR_HAVE_NO_MEMORY(addr_str); + NDR_CHECK(ndr_pull_array_uint8(ndr, ndr_flags, addr, IPV6_BYTES)); + for (i = 0; i < IPV6_BYTES; ++i) { + addr_str = talloc_asprintf_append(addr_str, "%02x", addr[i]); + NDR_ERR_HAVE_NO_MEMORY(addr_str); + /* We need a ':' every second byte but the last one */ + if (i%2 == 1 && i != (IPV6_BYTES - 1)) { + addr_str = talloc_strdup_append(addr_str, ":"); + NDR_ERR_HAVE_NO_MEMORY(addr_str); + } + } + *address = addr_str; + NDR_ERR_HAVE_NO_MEMORY(*address); + return NDR_ERR_SUCCESS; +} + +/* + push a ipv6address +*/ +_PUBLIC_ enum ndr_err_code ndr_push_ipv6address(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *address) +{ +#ifdef AF_INET6 + uint8_t addr[IPV6_BYTES]; + int ret; + + if (!is_ipaddress(address)) { + return ndr_push_error(ndr, NDR_ERR_IPV6ADDRESS, + "Invalid IPv6 address: '%s'", + address); + } + ret = inet_pton(AF_INET6, address, addr); + if (ret <= 0) { + return NDR_ERR_IPV6ADDRESS; + } + + NDR_CHECK(ndr_push_array_uint8(ndr, ndr_flags, addr, IPV6_BYTES)); + + return NDR_ERR_SUCCESS; +#else + return NDR_ERR_IPV6ADDRESS; +#endif +} + +/* + print a ipv6address +*/ +_PUBLIC_ void ndr_print_ipv6address(struct ndr_print *ndr, const char *name, + const char *address) +{ + ndr->print(ndr, "%-25s: %s", name, address); +} +#undef IPV6_BYTES + +_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_null(struct ndr_print *ndr) +{ + ndr->print(ndr, "UNEXPECTED NULL POINTER"); +} + +_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%"PRIX32")", name, val?val:"UNKNOWN_ENUM_VALUE", value); + } else { + ndr->print(ndr, "%-25s: %s (%"PRIu32")", 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) +{ + if (flag == 0) { + return; + } + + /* 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, " %"PRIu32": %-25s", value, flag_name); + } else { + ndr->print(ndr, "0x%02"PRIx32": %-25s (%"PRIu32")", value, flag_name, value); + } +} + +_PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: %"PRId8, name, v); +} + +_PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: 0x%02"PRIx8" (%"PRIu8")", name, v, v); +} + +_PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: %"PRId16, name, v); +} + +_PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: 0x%04"PRIx16" (%"PRIu16")", name, v, v); +} + +_PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: %"PRId32, name, v); +} + +_PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: 0x%08"PRIx32" (%"PRIu32")", name, v, v); +} + +_PUBLIC_ void ndr_print_int3264(struct ndr_print *ndr, const char *name, int32_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: %"PRId32, name, v); +} + +_PUBLIC_ void ndr_print_uint3264(struct ndr_print *ndr, const char *name, uint32_t v) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: 0x%08"PRIx32" (%"PRIu32")", name, v, v); +} + +_PUBLIC_ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr->print(ndr, "%-25s: 0x%016"PRIx64" (%"PRIu64")", name, v, 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) +{ + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + ndr->print(ndr, "%-25s: 0x%016"PRIx64" (%"PRId64")", name, v, v); +} + +_PUBLIC_ void ndr_print_double(struct ndr_print *ndr, const char *name, double v) +{ + ndr->print(ndr, "%-25s: %f", name, 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_int64(struct ndr_print *ndr, const char *name, int64_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_uid_t(struct ndr_print *ndr, const char *name, uid_t u) +{ + ndr_print_dlong(ndr, name, u); +} + +_PUBLIC_ void ndr_print_gid_t(struct ndr_print *ndr, const char *name, gid_t g) +{ + ndr_print_dlong(ndr, name, g); +} + +_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 %"PRIu16, level); +} + +_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, + const uint8_t *data, uint32_t count) +{ + uint32_t i; +#define _ONELINE_LIMIT 32 + + if (data == NULL) { + ndr->print(ndr, "%s: ARRAY(%"PRIu32") : NULL", name, count); + return; + } + + if (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%s: ARRAY(%"PRIu32"): ", name, count); + return; + } + + if (count <= _ONELINE_LIMIT && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) { + char s[(_ONELINE_LIMIT + 1) * 2]; + for (i=0;iprint(ndr, "%-25s: %s", name, s); + return; + } + + ndr->print(ndr, "%s: ARRAY(%"PRIu32")", name, count); + if (count > _ONELINE_LIMIT && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) { + ndr_dump_data(ndr, data, count); + return; + } + + ndr->depth++; + for (i=0;idepth--; +#undef _ONELINE_LIMIT +} + +static void ndr_print_dump_data_cb(const char *buf, void *private_data) +{ + struct ndr_print *ndr = (struct ndr_print *)private_data; + + ndr->print(ndr, "%s", buf); +} + +/* + ndr_print version of dump_data() + */ +static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len) +{ + if (NDR_HIDE_SECRET(ndr)) { + return; + } + ndr->no_newline = true; + dump_data_cb(buf, len, true, ndr_print_dump_data_cb, ndr); + ndr->no_newline = false; +} + + +_PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r) +{ + ndr->print(ndr, "%-25s: DATA_BLOB length=%zu", name, r.length); + if (r.length) { + ndr_dump_data(ndr, r.data, r.length); + } +} + + +/* + * Push a DATA_BLOB onto the wire. + * 1) When called with LIBNDR_FLAG_ALIGN* alignment flags set, push padding + * bytes _only_. The length is determined by the alignment required and the + * current ndr offset. + * 2) When called with the LIBNDR_FLAG_REMAINING flag, push the byte array to + * the ndr buffer. + * 3) Otherwise, push a uint3264 length _and_ a corresponding byte array to the + * ndr buffer. + */ +_PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, ndr_flags_type ndr_flags, DATA_BLOB blob) +{ + if (ndr->flags & LIBNDR_FLAG_REMAINING) { + /* nothing to do */ + } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) { + 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 { + NDR_CHECK(ndr_push_uint3264(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. + * 1) when called with LIBNDR_FLAG_ALIGN* alignment flags set, pull padding + * bytes _only_. The length is determined by the alignment required and the + * current ndr offset. + * 2) When called with the LIBNDR_FLAG_REMAINING flag, pull all remaining bytes + * from the ndr buffer. + * 3) Otherwise, pull a uint3264 length _and_ a corresponding byte array from the + * ndr buffer. + */ +_PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, ndr_flags_type ndr_flags, DATA_BLOB *blob) +{ + uint32_t length = 0; + + if (ndr->flags & LIBNDR_FLAG_REMAINING) { + length = ndr->data_size - ndr->offset; + } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + length = NDR_ALIGN(ndr, 8); + } + if (ndr->data_size - ndr->offset < length) { + length = ndr->data_size - ndr->offset; + } + } else { + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length)); + } + if (length == 0) { + /* skip the talloc for an empty blob */ + blob->data = NULL; + blob->length = 0; + return NDR_ERR_SUCCESS; + } + 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, ndr_flags_type 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_ 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; +} + +_PUBLIC_ int ndr_map_error2errno(enum ndr_err_code ndr_err) +{ + switch (ndr_err) { + case NDR_ERR_SUCCESS: + return 0; + case NDR_ERR_BUFSIZE: + return ENOSPC; + case NDR_ERR_TOKEN: + return EINVAL; + case NDR_ERR_ALLOC: + return ENOMEM; + case NDR_ERR_ARRAY_SIZE: + return EMSGSIZE; + case NDR_ERR_INVALID_POINTER: + return EINVAL; + case NDR_ERR_UNREAD_BYTES: + return EOVERFLOW; + default: + break; + } + + /* we should map all error codes to different status codes */ + return EINVAL; +} + +_PUBLIC_ enum ndr_err_code ndr_push_timespec(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct timespec *t) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec)); + NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_nsec)); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_timespec(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct timespec *t) +{ + uint64_t secs = 0; + uint32_t nsecs = 0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs)); + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &nsecs)); + t->tv_sec = secs; + t->tv_nsec = nsecs; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_timespec(struct ndr_print *ndr, const char *name, + const struct timespec *t) +{ + char *str = timestring(ndr, t->tv_sec); + ndr->print(ndr, "%-25s: %s.%ld", name, str, t->tv_nsec); + TALLOC_FREE(str); +} + +_PUBLIC_ enum ndr_err_code ndr_push_timeval(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct timeval *t) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec)); + NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_usec)); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_timeval(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct timeval *t) +{ + uint64_t secs = 0; + uint32_t usecs = 0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs)); + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &usecs)); + t->tv_sec = secs; + t->tv_usec = usecs; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_timeval(struct ndr_print *ndr, const char *name, + const struct timeval *t) +{ + ndr->print(ndr, "%-25s: %s.%ld", name, timestring(ndr, t->tv_sec), + (long)t->tv_usec); +} + +_PUBLIC_ void ndr_print_libndr_flags(struct ndr_print *ndr, const char *name, + libndr_flags flags) +{ + ndr->print(ndr, "%-25s: 0x%016"PRI_LIBNDR_FLAGS" (%"PRI_LIBNDR_FLAGS_DECIMAL")", name, flags, flags); +} diff --git a/librpc/ndr/ndr_bkupblobs.c b/librpc/ndr/ndr_bkupblobs.c new file mode 100644 index 0000000..34c1839 --- /dev/null +++ b/librpc/ndr/ndr_bkupblobs.c @@ -0,0 +1,82 @@ +/* + Unix SMB/CIFS implementation. + + helper routines for BKUP Blobs marshalling + + Copyright (C) Matthieu Patou 2011 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_bkupblobs.h" + + +_PUBLIC_ enum ndr_err_code ndr_push_bkup_NTBackupFile(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkup_NTBackupFile *r) +{ + uint32_t cntr_streams_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 2)); + for (cntr_streams_0 = 0; cntr_streams_0 < r->num_stream; cntr_streams_0++) { + NDR_CHECK(ndr_push_bkup_Win32StreamId(ndr, NDR_SCALARS, &r->streams[cntr_streams_0])); + } + NDR_CHECK(ndr_push_trailer_align(ndr, 8)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +#define _TMP_PULL_REALLOC_N(ndr, s, t, n) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_realloc(ndr->current_mem_ctx, (s), t, n); \ + if (!(s)) { \ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ + "Alloc %u * %s failed: %s\n", \ + (unsigned)n, # s, __location__); \ + } \ +} while (0) + +_PUBLIC_ enum ndr_err_code ndr_pull_bkup_NTBackupFile(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkup_NTBackupFile *r) +{ + uint32_t cntr_streams_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + uint32_t remaining = ndr->data_size - ndr->offset; + r->num_stream = 0; + r->streams = NULL; + for (cntr_streams_0 = 0; remaining > 0; cntr_streams_0++) { + r->num_stream += 1; + _TMP_PULL_REALLOC_N(ndr, r->streams, + struct bkup_Win32StreamId, + r->num_stream); + NDR_CHECK(ndr_pull_bkup_Win32StreamId(ndr, + NDR_SCALARS, + &r->streams[cntr_streams_0])); + remaining = ndr->data_size - ndr->offset; + } + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_cab.c b/librpc/ndr/ndr_cab.c new file mode 100644 index 0000000..ae3353b --- /dev/null +++ b/librpc/ndr/ndr_cab.c @@ -0,0 +1,442 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling cab structures + + Copyright (C) Guenther Deschner 2016 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_cab.h" +#include "librpc/ndr/ndr_compression.h" + +#define OFFSET_OF_FOLDER_COFFCABSTART(folder) (36 /* cfheader size */ + (size_t)(folder)*8) + +_PUBLIC_ void ndr_print_cf_time(struct ndr_print *ndr, const char *name, const struct cf_time *r) +{ + uint8_t hour = 0, minute = 0, seconds = 0; + char *s; + if (r == NULL) { ndr_print_null(ndr); return; } + hour = r->time >> 11; + minute = (r->time >> 5) & 0x3f; + seconds = (r->time << 1) & 0x3e; + s = talloc_asprintf(ndr, "%02d:%02d:%02d", hour, minute, seconds); + if (s == NULL) { return; } + ndr_print_string(ndr, "time", s); + talloc_free(s); +} + +_PUBLIC_ void ndr_print_cf_date(struct ndr_print *ndr, const char *name, const struct cf_date *r) +{ + uint16_t year = 0; + uint8_t month = 0, day = 0; + char *s; + if (r == NULL) { ndr_print_null(ndr); return; } + year = (r->date >> 9); + year += 1980; + month = (r->date >> 5 & 0xf); + day = (r->date & 0x1f); + s = talloc_asprintf(ndr, "%02"PRIu8"/%02"PRIu8"/%04"PRIu16, day, month, year); + if (s == NULL) { return; } + ndr_print_string(ndr, "date", s); + talloc_free(s); +} + +uint32_t ndr_count_cfdata(const struct cab_file *r) +{ + uint32_t count = 0, i; + + for (i = 0; i < r->cfheader.cFolders; i++) { + if (count + r->cffolders[i].cCFData < count) { + /* Integer wrap. */ + return 0; + } + count += r->cffolders[i].cCFData; + } + + return count; +} + +static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed) +{ + int num_ulong; + uint32_t checksum; + uint8_t *pb; + uint32_t ul; + + num_ulong = length / 4; + checksum = seed; + pb = data; + + while (num_ulong-- > 0) { + ul = (uint32_t)(*pb++); + ul |= (((uint32_t)(*pb++)) << 8); + ul |= (((uint32_t)(*pb++)) << 16); + ul |= (((uint32_t)(*pb++)) << 24); + + checksum ^= ul; + } + + ul = 0; + + switch (length % 4) { + case 3: + ul |= (((uint32_t)(*pb++)) << 16); + FALL_THROUGH; + case 2: + ul |= (((uint32_t)(*pb++)) << 8); + FALL_THROUGH; + case 1: + ul |= (uint32_t)(*pb++); + FALL_THROUGH; + default: + break; + } + + checksum ^= ul; + + return checksum; +} + +/* Push all CFDATA of a folder. + * + * This works on a folder level because compression type is set per + * folder, and a compression state can be shared between CFDATA of the + * same folder. + * + * This is not a regular NDR func as we pass the compression type and + * the number of CFDATA as extra arguments + */ +static enum ndr_err_code ndr_push_folder_cfdata(struct ndr_push *ndr, + const struct CFDATA *r, + enum cf_compress_type cab_ctype, + size_t num_cfdata) +{ + size_t i; + enum ndr_compression_alg ndr_ctype = 0; + + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN); + + if (cab_ctype == CF_COMPRESS_MSZIP) { + ndr_ctype = NDR_COMPRESSION_MSZIP_CAB; + NDR_CHECK(ndr_push_compression_state_init(ndr, ndr_ctype)); + } + + for (i = 0; i < num_cfdata; i++, r++) { + uint32_t compressed_length = 0; + uint32_t csum, csumPartial; + size_t compressed_offset, csum_offset, data_offset; + + if (!r->ab.data) { + return ndr_push_error(ndr, NDR_ERR_LENGTH, + "NULL uncompressed data blob"); + } + if (r->ab.length != r->cbUncomp) { + return ndr_push_error(ndr, NDR_ERR_LENGTH, + "Uncompressed data blob size != uncompressed data size field"); + } + + /* + * checksum is a function of the size fields + * and the potentially compressed data bytes, + * which haven't been compressed yet so + * remember offset, write zeroes, fill out + * later + */ + csum_offset = ndr->offset; + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + + /* + * similarly, we don't know the compressed + * size yet, remember offset, write zeros, + * fill out later + */ + compressed_offset = ndr->offset; + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->cbUncomp)); + + data_offset = ndr->offset; + + switch (cab_ctype) { + case CF_COMPRESS_NONE: + /* just copy the data */ + NDR_PUSH_NEED_BYTES(ndr, r->ab.length); + NDR_CHECK(ndr_push_bytes(ndr, r->ab.data, r->ab.length)); + compressed_length = r->ab.length; + break; + case CF_COMPRESS_LZX: + /* + * we have not yet worked out the details of LZX + * compression + */ + return NDR_ERR_COMPRESSION; + + case CF_COMPRESS_MSZIP: { + struct ndr_push *push_sub, *push_compress; + + /* compress via subcontext */ + NDR_CHECK(ndr_push_subcontext_start(ndr, &push_sub, 0, -1)); + + /* + * This assignment replaces a call to + * ndr_push_compression_state_init(push_sub, ndr_ctype)) + * here. This is instead done outside the loop. + */ + push_sub->cstate = ndr->cstate; + + NDR_CHECK(ndr_push_compression_start(push_sub, &push_compress)); + ndr_set_flags(&push_compress->flags, LIBNDR_FLAG_REMAINING); + NDR_CHECK(ndr_push_DATA_BLOB(push_compress, NDR_SCALARS, r->ab)); + NDR_CHECK(ndr_push_compression_end(push_sub, push_compress)); + NDR_CHECK(ndr_push_subcontext_end(ndr, push_sub, 0, -1)); + compressed_length = push_sub->offset; + + break; + } + default: + return NDR_ERR_BAD_SWITCH; + } + + /* we can now write the compressed size and the checksum */ + SSVAL(ndr->data, compressed_offset, compressed_length); + + /* + * Create checksum over compressed data. + * + * The 8 bytes are the header size. + * + * We have already have written the checksum and set it to zero, + * earlier. So we know that after the checksum end the value + * for the compressed length comes the blob data. + * + * NDR already did all the checks for integer wraps. + */ + csumPartial = ndr_cab_compute_checksum(&ndr->data[data_offset], + compressed_length, 0); + + /* + * Checksum over header (compressed and uncompressed length). + * + * The first 4 bytes are the checksum size. + * The second 4 bytes are the size of the compressed and + * uncompressed length fields. + * + * NDR already did all the checks for integer wraps. + */ + csum = ndr_cab_compute_checksum(&ndr->data[compressed_offset], + data_offset - compressed_offset, + csumPartial); + + SIVAL(ndr->data, csum_offset, csum); + } + + TALLOC_FREE(ndr->cstate); + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct cab_file *r) +{ + uint32_t cntr_cffolders_0; + uint32_t cntr_cffiles_0; + size_t processed_cfdata = 0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN); + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + + if (ndr_flags & NDR_SCALARS) { + uint32_t i; + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader)); + for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) { + NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0])); + } + for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) { + NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0])); + } +#if 0 + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r))); +#endif + + /* write in the folder header the offset of its first data block */ + for (i = 0; i < r->cfheader.cFolders; i++) { + size_t off = OFFSET_OF_FOLDER_COFFCABSTART(i); + /* check that the offset we want to + * write to is always inside our + * current push buffer + */ + if (off >= ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_OFFSET, + "trying to write past current push buffer size"); + } + SIVAL(ndr->data, off, ndr->offset); + NDR_CHECK(ndr_push_folder_cfdata(ndr, r->cfdata + processed_cfdata, r->cffolders[i].typeCompress, r->cffolders[i].cCFData)); + processed_cfdata += r->cffolders[i].cCFData; + } + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + + + /* write total file size in header */ + SIVAL(ndr->data, 8, ndr->offset); + + return NDR_ERR_SUCCESS; +} + + +/* Pull all CFDATA of a folder. + * + * This works on a folder level because compression type is set per + * folder, and a compression state can be shared between CFDATA of the + * same folder. + * + * This is not a regular NDR func as we pass the compression type and + * the number of CFDATA as extra arguments + */ +static enum ndr_err_code ndr_pull_folder_cfdata(struct ndr_pull *ndr, + struct CFDATA *r, + enum cf_compress_type cab_ctype, + size_t num_cfdata) +{ + size_t i; + enum ndr_compression_alg ndr_ctype = 0; + + if (cab_ctype == CF_COMPRESS_MSZIP) { + ndr_ctype = NDR_COMPRESSION_MSZIP_CAB; + NDR_CHECK(ndr_pull_compression_state_init(ndr, NDR_COMPRESSION_MSZIP_CAB, &ndr->cstate)); + } + + for (i = 0; i < num_cfdata; i++, r++) { + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->csum)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbData)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbUncomp)); + + switch (cab_ctype) { + case CF_COMPRESS_NONE: + /* just copy the data */ + NDR_PULL_NEED_BYTES(ndr, r->cbUncomp); + r->ab = data_blob_talloc(ndr->current_mem_ctx, + ndr->data+ndr->offset, + r->cbUncomp); + if (r->ab.data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "failed to allocate buffer for uncompressed CFDATA block"); + } + ndr->offset += r->cbUncomp; + break; + + case CF_COMPRESS_LZX: + /* just copy the data (LZX decompression not implemented yet) */ + NDR_PULL_NEED_BYTES(ndr, r->cbData); + r->ab = data_blob_talloc(ndr->current_mem_ctx, + ndr->data+ndr->offset, + r->cbData); + if (r->ab.data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "failed to allocate buffer for LZX-compressed CFDATA block"); + } + ndr->offset += r->cbData; + break; + + case CF_COMPRESS_MSZIP: { + struct ndr_pull *pull_sub, *pull_compress; + NDR_PULL_NEED_BYTES(ndr, r->cbData); + /* decompress via subcontext */ + NDR_CHECK(ndr_pull_subcontext_start(ndr, &pull_sub, 0, r->cbData)); + pull_sub->cstate = ndr->cstate; + NDR_CHECK(ndr_pull_compression_start(pull_sub, &pull_compress, + ndr_ctype, r->cbUncomp, r->cbData)); + ndr_set_flags(&pull_compress->flags, LIBNDR_FLAG_REMAINING); + NDR_CHECK(ndr_pull_DATA_BLOB(pull_compress, NDR_SCALARS, &r->ab)); + NDR_CHECK(ndr_pull_compression_end(pull_sub, pull_compress, ndr_ctype, r->cbUncomp)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, pull_sub, 0, r->cbData)); + + break; + } + default: + return NDR_ERR_BAD_SWITCH; + } + } + + TALLOC_FREE(ndr->cstate); + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cab_file *r) +{ + uint32_t size_cffolders_0 = 0; + uint32_t cntr_cffolders_0; + TALLOC_CTX *_mem_save_cffolders_0 = NULL; + uint32_t size_cffiles_0 = 0; + uint32_t cntr_cffiles_0; + TALLOC_CTX *_mem_save_cffiles_0 = NULL; + uint32_t size_cfdata_0 = 0; + size_t processed_cfdata = 0; + TALLOC_CTX *_mem_save_cfdata_0 = NULL; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN); + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_CFHEADER(ndr, NDR_SCALARS, &r->cfheader)); + size_cffolders_0 = r->cfheader.cFolders; + NDR_PULL_ALLOC_N(ndr, r->cffolders, size_cffolders_0); + _mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->cffolders, 0); + for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) { + NDR_CHECK(ndr_pull_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffolders_0, 0); + size_cffiles_0 = r->cfheader.cFiles; + NDR_PULL_ALLOC_N(ndr, r->cffiles, size_cffiles_0); + _mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->cffiles, 0); + for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (size_cffiles_0); cntr_cffiles_0++) { + NDR_CHECK(ndr_pull_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffiles_0, 0); +#if 0 + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cfdata_count)); +#else + r->cfdata_count = ndr_count_cfdata(r); +#endif + size_cfdata_0 = r->cfdata_count; + NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0); + _mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0); + for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) { + NDR_CHECK(ndr_pull_folder_cfdata(ndr, + r->cfdata + processed_cfdata, + r->cffolders[cntr_cffolders_0].typeCompress, + r->cffolders[cntr_cffolders_0].cCFData)); + processed_cfdata += r->cffolders[cntr_cffolders_0].cCFData; + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_cab.h b/librpc/ndr/ndr_cab.h new file mode 100644 index 0000000..39b6bc9 --- /dev/null +++ b/librpc/ndr/ndr_cab.h @@ -0,0 +1,22 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling cab structures + + Copyright (C) Guenther Deschner 2016 + + 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 . +*/ + +uint32_t ndr_count_cfdata(const struct cab_file *r); diff --git a/librpc/ndr/ndr_claims.c b/librpc/ndr/ndr_claims.c new file mode 100644 index 0000000..9612626 --- /dev/null +++ b/librpc/ndr/ndr_claims.c @@ -0,0 +1,90 @@ +#include "includes.h" +#include "librpc/gen_ndr/ndr_claims.h" +#include "librpc/ndr/ndr_claims.h" + +#include "librpc/ndr/ndr_compression.h" +#include "lib/compression/lzxpress_huffman.h" + +enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg) +{ + switch (wire_alg) { + case CLAIMS_COMPRESSION_FORMAT_NONE: + return NDR_COMPRESSION_NONE; + + case CLAIMS_COMPRESSION_FORMAT_LZNT1: + return NDR_COMPRESSION_INVALID; + + case CLAIMS_COMPRESSION_FORMAT_XPRESS: + return NDR_COMPRESSION_INVALID; + + case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF: + return NDR_COMPRESSION_XPRESS_HUFF_RAW; + } + return NDR_COMPRESSION_INVALID; +} + + +enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression, + size_t uncompressed_claims_size) { + if (uncompressed_claims_size < CLAIM_UPPER_COMPRESSION_THRESHOLD) { + return CLAIMS_COMPRESSION_FORMAT_NONE; + } + + return specified_compression; +} + +size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set, + enum CLAIMS_COMPRESSION_FORMAT wire_alg, + int flags) +{ + TALLOC_CTX *frame = NULL; + DATA_BLOB tmp_blob; + uint8_t * tmp_compressed; + ssize_t compressed_size; + enum ndr_err_code ndr_err; + enum CLAIMS_COMPRESSION_FORMAT actual_wire_alg; + + if (claims_set == NULL) { + return 0; + } + + frame = talloc_stackframe(); + + ndr_err = ndr_push_struct_blob(&tmp_blob, + frame, + claims_set, + (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_NDR); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DBG_ERR("Failed to push claims while determining compressed size\n"); + TALLOC_FREE(frame); + return 0; + } + + actual_wire_alg = ndr_claims_actual_wire_compression_alg(wire_alg, + tmp_blob.length); + + switch (actual_wire_alg) { + case CLAIMS_COMPRESSION_FORMAT_NONE: + TALLOC_FREE(frame); + return tmp_blob.length; + + case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF: + compressed_size = lzxpress_huffman_compress_talloc(frame, + tmp_blob.data, + tmp_blob.length, + &tmp_compressed); + + TALLOC_FREE(frame); + + if (compressed_size < 0) { + DBG_ERR("Failed to compress claims (for determining compressed size)\n"); + return 0; + } + return compressed_size; + + default: + TALLOC_FREE(frame); + DBG_ERR("Invalid chosen compression algorithm while determining compressed claim size\n"); + return 0; + } +} diff --git a/librpc/ndr/ndr_claims.h b/librpc/ndr/ndr_claims.h new file mode 100644 index 0000000..03f4046 --- /dev/null +++ b/librpc/ndr/ndr_claims.h @@ -0,0 +1,34 @@ +/* + Unix SMB/CIFS implementation. + + routines for helping the compression in claims + + Copyright (C) Andrew Bartlett 2023 + + 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 . +*/ + +#ifndef _LIBRPC_NDR_NDR_CLAIMS_H +#define _LIBRPC_NDR_NDR_CLAIMS_H + +enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg); +enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression, + size_t uncompressed_claims_size); + +size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set, + enum CLAIMS_COMPRESSION_FORMAT wire_alg, + int flags); + + +#endif /* _LIBRPC_NDR_NDR_CLAIMS_H */ diff --git a/librpc/ndr/ndr_compression.c b/librpc/ndr/ndr_compression.c new file mode 100644 index 0000000..6630b51 --- /dev/null +++ b/librpc/ndr/ndr_compression.c @@ -0,0 +1,1092 @@ +/* + Unix SMB/CIFS implementation. + + libndr compression support + + Copyright (C) Stefan Metzmacher 2005 + Copyright (C) Matthieu Suiche 2008 + + 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 . +*/ + +#include "includes.h" +#include "../lib/compression/lzxpress.h" +#include "../lib/compression/lzxpress_huffman.h" +#include "librpc/ndr/libndr.h" +#include "../librpc/ndr/ndr_compression.h" +#include + +struct ndr_compression_state { + enum ndr_compression_alg type; + union { + struct { + struct z_stream_s *z; + uint8_t *dict; + size_t dict_size; + } mszip; + struct { + struct lzxhuff_compressor_mem *mem; + } lzxpress_huffman; + } alg; +}; + +static voidpf ndr_zlib_alloc(voidpf opaque, uInt items, uInt size) +{ + return talloc_zero_size(opaque, items * size); +} + +static void ndr_zlib_free(voidpf opaque, voidpf address) +{ + talloc_free(address); +} + +static enum ndr_err_code ndr_pull_compression_mszip_cab_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + struct ndr_compression_state *state, + ssize_t decompressed_len, + ssize_t compressed_len) +{ + 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; + z_stream *z = state->alg.mszip.z; + int z_ret; + + plain_chunk_size = decompressed_len; + + if (plain_chunk_size > 0x00008000) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad MSZIP CAB plain chunk size %08"PRIX32" > 0x00008000 (PULL)", + plain_chunk_size); + } + + + comp_chunk_size = compressed_len; + + DEBUG(9,("MSZIP CAB plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\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; + + if (comp_chunk.length < 2) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad MSZIP CAB comp chunk size %zu < 2 (PULL)", + comp_chunk.length); + } + /* CK = Chris Kirmse, official Microsoft purloiner */ + if (comp_chunk.data[0] != 'C' || + comp_chunk.data[1] != 'K') { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad MSZIP CAB invalid prefix [%c%c] != [CK]", + comp_chunk.data[0], comp_chunk.data[1]); + } + + /* + * This is a MSZIP block. It is actually using the deflate + * algorithm which can be decompressed by zlib. zlib will try + * to decompress as much as it can in each run. If we provide + * all the input and enough room for the uncompressed output, + * one call is enough. It will loop over all the sub-blocks + * that make up a deflate block. + * + * See corresponding push function for more info. + */ + + z->next_in = comp_chunk.data + 2; + z->avail_in = comp_chunk.length - 2; + z->next_out = plain_chunk.data; + z->avail_out = plain_chunk.length; + + /* + * Each MSZIP CDATA contains a complete deflate stream + * i.e. the stream starts and ends in the CFDATA but the + * _dictionary_ is shared between all CFDATA of a CFFOLDER. + * + * When decompressing, the initial dictionary of the first + * CDATA is empty. All other CFDATA use the previous CFDATA + * uncompressed output as dictionary. + */ + + if (state->alg.mszip.dict_size) { + z_ret = inflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib inflateSetDictionary error %s (%d) %s (PULL)", + zError(z_ret), z_ret, z->msg); + } + } + + z_ret = inflate(z, Z_FINISH); + if (z_ret == Z_OK) { + /* + * Z_OK here means there was no error but the stream + * hasn't been fully decompressed because there was + * not enough room for the output, which should not + * happen + */ + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib inflate error not enough space for output (PULL)"); + } + if (z_ret != Z_STREAM_END) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib inflate error %s (%d) %s (PULL)", zError(z_ret), z_ret, z->msg); + } + + if (z->total_out < plain_chunk.length) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)", + z->total_out, plain_chunk.length); + } + + /* + * Keep a copy of the output to set as dictionary for the + * next decompression call. + * + * The input pointer seems to be still valid between calls, so + * we can just store that instead of copying the memory over + * the dict temp buffer. + */ + state->alg.mszip.dict = plain_chunk.data; + state->alg.mszip.dict_size = plain_chunk.length; + + z_ret = inflateReset(z); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib inflateReset error %s (%d) %s (PULL)", + zError(z_ret), z_ret, z->msg); + } + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_mszip_cab_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + struct ndr_compression_state *state) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_size; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + uint32_t max_plain_size = 0x00008000; + /* + * The maximum compressed size of each MSZIP block is 32k + 12 bytes + * header size. + */ + uint32_t max_comp_size = 0x00008000 + 12; + int z_ret; + z_stream *z; + + if (ndrpull->data_size <= ndrpull->offset) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "strange NDR pull size and offset (integer overflow?)"); + + } + + plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset); + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size)); + + comp_chunk.data = ndrpush->data + ndrpush->offset; + comp_chunk.length = max_comp_size; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + comp_chunk.data[0] = 'C'; + comp_chunk.data[1] = 'K'; + + z = state->alg.mszip.z; + z->next_in = plain_chunk.data; + z->avail_in = plain_chunk.length; + z->total_in = 0; + + z->next_out = comp_chunk.data + 2; + z->avail_out = comp_chunk.length; + z->total_out = 0; + + /* + * See pull function for explanations of the MSZIP format. + * + * The CFDATA block contains a full deflate stream. Each stream + * uses the uncompressed input of the previous CFDATA in the + * same CFFOLDER as a dictionary for the compression. + */ + + if (state->alg.mszip.dict_size) { + z_ret = deflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib deflateSetDictionary error %s (%d) %s (PUSH)", + zError(z_ret), z_ret, z->msg); + } + } + + /* + * Z_FINISH should make deflate process all of the input in + * one call. If the stream is not finished there was an error + * e.g. not enough room to store the compressed output. + */ + z_ret = deflate(z, Z_FINISH); + if (z_ret != Z_STREAM_END) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "zlib deflate error %s (%d) %s (PUSH)", + zError(z_ret), z_ret, z->msg); + } + + if (z->avail_in) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "MSZIP not all avail_in[%u] bytes consumed (PUSH)", + z->avail_in); + } + + comp_chunk_size = 2 + z->total_out; + if (comp_chunk_size < z->total_out) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "strange NDR push compressed size (integer overflow?)"); + } + + z_ret = deflateReset(z); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib deflateReset error %s (%d) %s (PUSH)", + zError(z_ret), z_ret, z->msg); + } + + if (plain_chunk.length > talloc_array_length(state->alg.mszip.dict)) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "zlib dict buffer is too big (PUSH)"); + } + + /* + * Keep a copy of the input to set as dictionary for the next + * compression call. + * + * Ideally we would just store the input pointer and length + * without copying but the memory gets invalidated between the + * calls, so we just copy to a dedicated buffer we know is + * still going to be valid for the lifetime of the + * compressions state object. + */ + memcpy(state->alg.mszip.dict, plain_chunk.data, plain_chunk.length); + state->alg.mszip.dict_size = plain_chunk.length; + + DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n", + plain_chunk.length, + plain_chunk.length, + comp_chunk_size, comp_chunk_size)); + + ndrpush->offset += comp_chunk_size; + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + z_stream *z, + 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 z_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 %08"PRIX32" > 0x00008000 (PULL)", + plain_chunk_size); + } + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size)); + + DEBUG(9,("MSZIP plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\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; + + if (comp_chunk.length < 2) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad MSZIP comp chunk size %zu < 2 (PULL)", + comp_chunk.length); + } + /* CK = Chris Kirmse, official Microsoft purloiner */ + if (comp_chunk.data[0] != 'C' || + comp_chunk.data[1] != 'K') { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad MSZIP invalid prefix [%c%c] != [CK]", + comp_chunk.data[0], comp_chunk.data[1]); + } + + z->next_in = comp_chunk.data + 2; + z->avail_in = comp_chunk.length -2; + z->total_in = 0; + + z->next_out = plain_chunk.data; + z->avail_out = plain_chunk.length; + z->total_out = 0; + + if (!z->opaque) { + /* the first time we need to initialize completely */ + z->zalloc = ndr_zlib_alloc; + z->zfree = ndr_zlib_free; + z->opaque = ndrpull; + + z_ret = inflateInit2(z, -MAX_WBITS); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad inflateInit2 error %s(%d) (PULL)", + zError(z_ret), z_ret); + + } + } + + /* call inflate until we get Z_STREAM_END or an error */ + while (true) { + z_ret = inflate(z, Z_BLOCK); + if (z_ret != Z_OK) break; + } + + if (z_ret != Z_STREAM_END) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad inflate(Z_BLOCK) error %s(%d) (PULL)", + zError(z_ret), z_ret); + } + + if (z->avail_in) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "MSZIP not all avail_in[%u] bytes consumed (PULL)", + z->avail_in); + } + + if (z->avail_out) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "MSZIP not all avail_out[%u] bytes consumed (PULL)", + z->avail_out); + } + + if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) { + /* this is the last chunk */ + *last = true; + } + + z_ret = inflateReset(z); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad inflateReset error %s(%d) (PULL)", + zError(z_ret), z_ret); + } + + z_ret = inflateSetDictionary(z, plain_chunk.data, plain_chunk.length); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad inflateSetDictionary error %s(%d) (PULL)", + zError(z_ret), z_ret); + } + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + z_stream *z, + bool *last) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_size; + uint32_t comp_chunk_size_offset; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + uint32_t max_plain_size = 0x00008000; + /* + * The maximum compressed size of each MSZIP block is 32k + 12 bytes + * header size. + */ + uint32_t max_comp_size = 0x00008000 + 12; + uint32_t tmp_offset; + int z_ret; + + plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset); + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + if (plain_chunk_size < max_plain_size) { + *last = true; + } + + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size)); + comp_chunk_size_offset = ndrpush->offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE)); + + NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size)); + + comp_chunk.data = ndrpush->data + ndrpush->offset; + comp_chunk.length = max_comp_size; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + comp_chunk.data[0] = 'C'; + comp_chunk.data[1] = 'K'; + + z->next_in = plain_chunk.data; + z->avail_in = plain_chunk.length; + z->total_in = 0; + + z->next_out = comp_chunk.data + 2; + z->avail_out = comp_chunk.length; + z->total_out = 0; + + if (!z->opaque) { + /* the first time we need to initialize completely */ + z->zalloc = ndr_zlib_alloc; + z->zfree = ndr_zlib_free; + z->opaque = ndrpull; + + /* TODO: find how to trigger the same parameters windows uses */ + z_ret = deflateInit2(z, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + -MAX_WBITS, + 8, /* memLevel */ + Z_DEFAULT_STRATEGY); + if (z_ret != Z_OK) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "Bad deflateInit2 error %s(%d) (PUSH)", + zError(z_ret), z_ret); + + } + } + + /* call deflate until we get Z_STREAM_END or an error */ + while (true) { + z_ret = deflate(z, Z_FINISH); + if (z_ret != Z_OK) break; + } + if (z_ret != Z_STREAM_END) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "Bad deflate(Z_BLOCK) error %s(%d) (PUSH)", + zError(z_ret), z_ret); + } + + if (z->avail_in) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "MSZIP not all avail_in[%u] bytes consumed (PUSH)", + z->avail_in); + } + + comp_chunk_size = 2 + z->total_out; + + z_ret = deflateReset(z); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad deflateReset error %s(%d) (PULL)", + zError(z_ret), z_ret); + } + + z_ret = deflateSetDictionary(z, plain_chunk.data, plain_chunk.length); + if (z_ret != Z_OK) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "Bad deflateSetDictionary error %s(%d) (PULL)", + zError(z_ret), z_ret); + } + + tmp_offset = ndrpush->offset; + ndrpush->offset = comp_chunk_size_offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size)); + ndrpush->offset = tmp_offset; + + DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n", + plain_chunk.length, + plain_chunk.length, + comp_chunk_size, comp_chunk_size)); + + ndrpush->offset += comp_chunk_size; + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + bool *last) +{ + DATA_BLOB comp_chunk; + DATA_BLOB plain_chunk; + uint32_t comp_chunk_offset; + uint32_t plain_chunk_offset; + uint32_t comp_chunk_size; + uint32_t plain_chunk_size; + ssize_t ret; + + 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 %08"PRIX32" > 0x00010000 (PULL)", + plain_chunk_size); + } + + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &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; + + DEBUG(9,("XPRESS plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n", + plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size)); + + /* Uncompressing the buffer using LZ Xpress algorithm */ + ret = lzxpress_decompress(comp_chunk.data, + comp_chunk.length, + plain_chunk.data, + plain_chunk.length); + if (ret < 0) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS lzxpress_decompress() returned %zd\n", + ret); + } + plain_chunk.length = ret; + + 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_push_compression_xpress_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + bool *last) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_size_offset; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + uint32_t max_plain_size = 0x00010000; + uint32_t max_comp_size = 0x00020000 + 2; /* TODO: use the correct value here */ + uint32_t tmp_offset; + ssize_t ret; + + plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset); + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + if (plain_chunk_size < max_plain_size) { + *last = true; + } + + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size)); + comp_chunk_size_offset = ndrpush->offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE)); + + NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size)); + + comp_chunk.data = ndrpush->data + ndrpush->offset; + comp_chunk.length = max_comp_size; + + /* Compressing the buffer using LZ Xpress algorithm */ + ret = lzxpress_compress(plain_chunk.data, + plain_chunk.length, + comp_chunk.data, + comp_chunk.length); + if (ret < 0) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS lzxpress_compress() returned %zd\n", + ret); + } + comp_chunk.length = ret; + + tmp_offset = ndrpush->offset; + ndrpush->offset = comp_chunk_size_offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk.length)); + ndrpush->offset = tmp_offset; + + ndrpush->offset += comp_chunk.length; + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_compression_none(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + ssize_t decompressed_len, + ssize_t compressed_len) +{ + DATA_BLOB comp_chunk; + uint32_t comp_chunk_size = compressed_len; + uint32_t comp_chunk_offset; + + if (decompressed_len != compressed_len) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "decompressed len %zd != compressed_len %zd in 'NONE' compression!", + decompressed_len, + compressed_len); + } + + if (comp_chunk_size != compressed_len) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "compressed_len %zd overflows uint32_t in 'NONE' compression!", + compressed_len); + } + + 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; + + NDR_CHECK(ndr_push_array_uint8(ndrpush, + NDR_SCALARS, + comp_chunk.data, + comp_chunk.length)); + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_none(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull) +{ + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + + plain_chunk_size = ndrpull->data_size - ndrpull->offset; + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + NDR_CHECK(ndr_push_array_uint8(ndrpush, + NDR_SCALARS, + plain_chunk.data, + plain_chunk.length)); + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_pull_compression_xpress_huff_raw_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + ssize_t decompressed_len, + ssize_t compressed_len) +{ + 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; + ssize_t ret; + + plain_chunk_size = decompressed_len; + comp_chunk_size = compressed_len; + + DEBUG(9,("XPRESS_HUFF 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; + + /* Decompressing the buffer using LZ Xpress w/ Huffman algorithm */ + ret = lzxpress_huffman_decompress(comp_chunk.data, + comp_chunk.length, + plain_chunk.data, + plain_chunk.length); + if (ret < 0) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS HUFF lzxpress_huffman_decompress() returned %zd\n", + ret); + } + + if (plain_chunk.length != ret) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS HUFF lzxpress_huffman_decompress() output is not as expected (%zd != %zu) (PULL)", + ret, plain_chunk.length); + } + + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code ndr_push_compression_xpress_huff_raw_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + struct ndr_compression_state *state) +{ + DATA_BLOB comp_chunk; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + ssize_t ret; + + struct lzxhuff_compressor_mem *mem = state->alg.lzxpress_huffman.mem; + + if (ndrpull->data_size <= ndrpull->offset) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "strange NDR pull size and offset (integer overflow?)"); + + } + + plain_chunk_size = ndrpull->data_size - ndrpull->offset; + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + comp_chunk.length = lzxpress_huffman_max_compressed_size(plain_chunk_size); + NDR_CHECK(ndr_push_expand(ndrpush, comp_chunk.length)); + + comp_chunk.data = ndrpush->data + ndrpush->offset; + + + /* Compressing the buffer using LZ Xpress w/ Huffman algorithm */ + ret = lzxpress_huffman_compress(mem, + plain_chunk.data, + plain_chunk.length, + comp_chunk.data, + comp_chunk.length); + if (ret < 0) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS HUFF lzxpress_huffman_compress() returned %zd\n", + ret); + } + + if (ret > comp_chunk.length) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, + "XPRESS HUFF lzxpress_huffman_compress() output is not as expected (%zd > %zu) (PULL)", + ret, comp_chunk.length); + } + + ndrpush->offset += ret; + return NDR_ERR_SUCCESS; +} + + +/* + 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, + ssize_t compressed_len) +{ + struct ndr_push *ndrpush; + struct ndr_pull *comndr; + DATA_BLOB uncompressed; + bool last = false; + z_stream z; + + ndrpush = ndr_push_init_ctx(subndr); + NDR_ERR_HAVE_NO_MEMORY(ndrpush); + + switch (compression_alg) { + case NDR_COMPRESSION_NONE: + NDR_CHECK(ndr_pull_compression_none(subndr, ndrpush, + decompressed_len, + compressed_len)); + break; + case NDR_COMPRESSION_MSZIP_CAB: + NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr, ndrpush, + subndr->cstate, + decompressed_len, + compressed_len)); + break; + case NDR_COMPRESSION_MSZIP: + ZERO_STRUCT(z); + while (!last) { + NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, &z, &last)); + } + break; + + case NDR_COMPRESSION_XPRESS: + while (!last) { + NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last)); + } + break; + + case NDR_COMPRESSION_XPRESS_HUFF_RAW: + NDR_CHECK(ndr_pull_compression_xpress_huff_raw_chunk(subndr, ndrpush, + decompressed_len, + compressed_len)); + break; + + default: + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)", + compression_alg); + } + + uncompressed = ndr_push_blob(ndrpush); + if (uncompressed.length != decompressed_len) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, + "Bad uncompressed_len [%zu] != [%zd](0x%08zX) (PULL)", + uncompressed.length, + decompressed_len, + 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; + + *_comndr = comndr; + 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 **_uncomndr) +{ + struct ndr_push *uncomndr; + enum ndr_compression_alg compression_alg = subndr->cstate->type; + + switch (compression_alg) { + case NDR_COMPRESSION_NONE: + case NDR_COMPRESSION_MSZIP_CAB: + case NDR_COMPRESSION_MSZIP: + case NDR_COMPRESSION_XPRESS: + case NDR_COMPRESSION_XPRESS_HUFF_RAW: + break; + default: + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, + "Bad compression algorithm %d (PUSH)", + compression_alg); + } + + uncomndr = ndr_push_init_ctx(subndr); + NDR_ERR_HAVE_NO_MEMORY(uncomndr); + uncomndr->flags = subndr->flags; + + *_uncomndr = uncomndr; + return NDR_ERR_SUCCESS; +} + +/* + push a compressed subcontext +*/ +enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr, + struct ndr_push *uncomndr) +{ + struct ndr_pull *ndrpull; + bool last = false; + z_stream z; + + enum ndr_compression_alg compression_alg = subndr->cstate->type; + + ndrpull = talloc_zero(uncomndr, struct ndr_pull); + NDR_ERR_HAVE_NO_MEMORY(ndrpull); + ndrpull->flags = uncomndr->flags; + ndrpull->data = uncomndr->data; + ndrpull->data_size = uncomndr->offset; + ndrpull->offset = 0; + + switch (compression_alg) { + case NDR_COMPRESSION_NONE: + NDR_CHECK(ndr_push_compression_none(subndr, ndrpull)); + break; + + case NDR_COMPRESSION_MSZIP_CAB: + NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr, ndrpull, subndr->cstate)); + break; + + case NDR_COMPRESSION_MSZIP: + ZERO_STRUCT(z); + while (!last) { + NDR_CHECK(ndr_push_compression_mszip_chunk(subndr, ndrpull, &z, &last)); + } + break; + + case NDR_COMPRESSION_XPRESS: + while (!last) { + NDR_CHECK(ndr_push_compression_xpress_chunk(subndr, ndrpull, &last)); + } + break; + + case NDR_COMPRESSION_XPRESS_HUFF_RAW: + NDR_CHECK(ndr_push_compression_xpress_huff_raw_chunk(subndr, ndrpull, subndr->cstate)); + break; + + default: + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)", + compression_alg); + } + + talloc_free(uncomndr); + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code generic_mszip_init(struct ndr_compression_state *state) +{ + z_stream *z = talloc_zero(state, z_stream); + NDR_ERR_HAVE_NO_MEMORY(z); + + z->zalloc = ndr_zlib_alloc; + z->zfree = ndr_zlib_free; + z->opaque = state; + + state->alg.mszip.z = z; + state->alg.mszip.dict_size = 0; + /* pre-alloc dictionary */ + state->alg.mszip.dict = talloc_array(state, uint8_t, 0x8000); + NDR_ERR_HAVE_NO_MEMORY(state->alg.mszip.dict); + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr, + enum ndr_compression_alg compression_alg, + struct ndr_compression_state **state) +{ + struct ndr_compression_state *s; + int z_ret; + + s = talloc_zero(ndr, struct ndr_compression_state); + NDR_ERR_HAVE_NO_MEMORY(s); + s->type = compression_alg; + + switch (compression_alg) { + case NDR_COMPRESSION_NONE: + case NDR_COMPRESSION_MSZIP: + case NDR_COMPRESSION_XPRESS: + case NDR_COMPRESSION_XPRESS_HUFF_RAW: + break; + case NDR_COMPRESSION_MSZIP_CAB: + NDR_CHECK(generic_mszip_init(s)); + z_ret = inflateInit2(s->alg.mszip.z, -MAX_WBITS); + if (z_ret != Z_OK) { + return ndr_pull_error(ndr, NDR_ERR_COMPRESSION, + "zlib inflateinit2 error %s (%d) %s (PULL)", + zError(z_ret), z_ret, s->alg.mszip.z->msg); + } + break; + default: + return ndr_pull_error(ndr, NDR_ERR_COMPRESSION, + "Bad compression algorithm %d (PULL)", + compression_alg); + break; + } + + *state = s; + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr, + enum ndr_compression_alg compression_alg) +{ + struct ndr_compression_state *s; + int z_ret; + + /* + * Avoid confusion, NULL out ndr->cstate at the start of the + * compression block + */ + ndr->cstate = NULL; + + s = talloc_zero(ndr, struct ndr_compression_state); + NDR_ERR_HAVE_NO_MEMORY(s); + s->type = compression_alg; + + switch (compression_alg) { + case NDR_COMPRESSION_NONE: + case NDR_COMPRESSION_XPRESS: + break; + + case NDR_COMPRESSION_XPRESS_HUFF_RAW: + s->alg.lzxpress_huffman.mem = talloc(s, struct lzxhuff_compressor_mem); + if (s->alg.lzxpress_huffman.mem == NULL) { + return NDR_ERR_ALLOC; + } + break; + + case NDR_COMPRESSION_MSZIP: + break; + case NDR_COMPRESSION_MSZIP_CAB: + NDR_CHECK(generic_mszip_init(s)); + z_ret = deflateInit2(s->alg.mszip.z, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + -MAX_WBITS, + 8, /* memLevel */ + Z_DEFAULT_STRATEGY); + if (z_ret != Z_OK) { + return ndr_push_error(ndr, NDR_ERR_COMPRESSION, + "zlib inflateinit2 error %s (%d) %s (PUSH)", + zError(z_ret), z_ret, s->alg.mszip.z->msg); + } + break; + default: + return ndr_push_error(ndr, NDR_ERR_COMPRESSION, + "Bad compression algorithm %d (PUSH)", + compression_alg); + break; + } + + ndr->cstate = s; + + return NDR_ERR_SUCCESS; +} + diff --git a/librpc/ndr/ndr_compression.h b/librpc/ndr/ndr_compression.h new file mode 100644 index 0000000..3d335b2 --- /dev/null +++ b/librpc/ndr/ndr_compression.h @@ -0,0 +1,60 @@ +/* + Unix SMB/CIFS implementation. + + libndr compression support + + Copyright (C) Stefan Metzmacher 2005 + Copyright (C) Matthieu Suiche 2008 + + 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 . +*/ + +#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 contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + +/* 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, + ssize_t compressed_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 **_uncomndr); +enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr, + struct ndr_push *uncomndr); + +enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr, + enum ndr_compression_alg compression_alg, + struct ndr_compression_state **state); +void ndr_pull_compression_state_free(struct ndr_compression_state *state); +enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr, + enum ndr_compression_alg compression_alg); + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __LIBRPC_NDR_NDR_COMPRESSION_H__ */ + diff --git a/librpc/ndr/ndr_dcerpc.c b/librpc/ndr/ndr_dcerpc.c new file mode 100644 index 0000000..b368bfa --- /dev/null +++ b/librpc/ndr/ndr_dcerpc.c @@ -0,0 +1,316 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in the DCERPC protocol + + Copyright (C) Stefan Metzmacher 2014 + Copyright (C) Gregor Beck 2014 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" +#include "librpc/gen_ndr/ndr_misc.h" + +_PUBLIC_ enum ndr_err_code ndr_push_ncacn_packet(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct ncacn_packet *r) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->rpc_vers)); + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->rpc_vers_minor)); + NDR_CHECK(ndr_push_dcerpc_pkt_type(ndr, NDR_SCALARS, r->ptype)); + NDR_CHECK(ndr_push_dcerpc_pfc_flags(ndr, NDR_SCALARS, r->pfc_flags)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->drep, 4)); + if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) { + ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT; + } + if (!(r->drep[0] & DCERPC_DREP_LE)) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->frag_length)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->auth_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->call_id)); + NDR_CHECK(ndr_push_set_switch_value(ndr, &r->u, r->ptype)); + NDR_CHECK(ndr_push_dcerpc_payload(ndr, NDR_SCALARS, &r->u)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_ncacn_packet(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ncacn_packet *r) +{ + uint32_t size_drep_0 = 0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->rpc_vers)); + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->rpc_vers_minor)); + NDR_CHECK(ndr_pull_dcerpc_pkt_type(ndr, NDR_SCALARS, &r->ptype)); + NDR_CHECK(ndr_pull_dcerpc_pfc_flags(ndr, NDR_SCALARS, &r->pfc_flags)); + size_drep_0 = 4; + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->drep, size_drep_0)); + if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) { + ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT; + } + if (!(r->drep[0] & DCERPC_DREP_LE)) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->frag_length)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->auth_length)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->call_id)); + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->u, r->ptype)); + NDR_CHECK(ndr_pull_dcerpc_payload(ndr, NDR_SCALARS, &r->u)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_ncacn_packet(struct ndr_print *ndr, const char *name, const struct ncacn_packet *r) +{ + ndr_print_struct(ndr, name, "ncacn_packet"); + if (r == NULL) { ndr_print_null(ndr); return; } + ndr->depth++; + ndr_print_uint8(ndr, "rpc_vers", r->rpc_vers); + ndr_print_uint8(ndr, "rpc_vers_minor", r->rpc_vers_minor); + ndr_print_dcerpc_pkt_type(ndr, "ptype", r->ptype); + ndr_print_dcerpc_pfc_flags(ndr, "pfc_flags", r->pfc_flags); + ndr_print_array_uint8(ndr, "drep", r->drep, 4); + if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) { + ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT; + } + if (!(r->drep[0] & DCERPC_DREP_LE)) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + ndr_print_uint16(ndr, "frag_length", r->frag_length); + ndr_print_uint16(ndr, "auth_length", r->auth_length); + ndr_print_uint32(ndr, "call_id", r->call_id); + ndr_print_set_switch_value(ndr, &r->u, r->ptype); + ndr_print_dcerpc_payload(ndr, "u", &r->u); + ndr->depth--; +} + +/* + * This function was generated by pidl and + * has been extended by the (_available == 0) check. + * + * That's why we ignore the 80 char per line limit. + */ +enum ndr_err_code ndr_pull_dcerpc_bind_nak(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dcerpc_bind_nak *r) +{ + uint32_t size_versions_0 = 0; + uint32_t cntr_versions_0; + TALLOC_CTX *_mem_save_versions_0 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + uint32_t _available; + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_dcerpc_bind_nak_reason(ndr, NDR_SCALARS, &r->reject_reason)); + _available = ndr->data_size - ndr->offset; + if (_available == 0) { + /* + * This works around a bug in older + * Samba (<= 4.1) releases. + * + * See bug #11327. + */ + r->num_versions = 0; + } else { + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_versions)); + } + size_versions_0 = r->num_versions; + NDR_PULL_ALLOC_N(ndr, r->versions, size_versions_0); + _mem_save_versions_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->versions, 0); + for (cntr_versions_0 = 0; cntr_versions_0 < (size_versions_0); cntr_versions_0++) { + NDR_CHECK(ndr_pull_dcerpc_bind_nak_version(ndr, NDR_SCALARS, &r->versions[cntr_versions_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_versions_0, 0); + { + libndr_flags _flags_save_DATA_BLOB = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING); + NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad)); + ndr->flags = _flags_save_DATA_BLOB; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +const uint8_t DCERPC_SEC_VT_MAGIC[] = {0x8a,0xe3,0x13,0x71,0x02,0xf4,0x36,0x71}; + +_PUBLIC_ enum ndr_err_code ndr_push_dcerpc_sec_vt_count(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dcerpc_sec_vt_count *r) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + /* nothing */ + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_dcerpc_sec_vt_count(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dcerpc_sec_vt_count *r) +{ + uint32_t _saved_ofs = ndr->offset; + + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + r->count = 0; + + while (true) { + uint16_t command; + uint16_t length; + + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &command)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &length)); + NDR_CHECK(ndr_pull_advance(ndr, length)); + + r->count += 1; + + if (command & DCERPC_SEC_VT_COMMAND_END) { + break; + } + } + + ndr->offset = _saved_ofs; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer( + struct ndr_pull *ndr, TALLOC_CTX *mem_ctx, + struct dcerpc_sec_verification_trailer **_r) +{ + enum ndr_err_code ndr_err; + uint32_t ofs; + uint32_t min_ofs = 0; + struct dcerpc_sec_verification_trailer *r; + DATA_BLOB sub_blob = data_blob_null; + struct ndr_pull *sub_ndr = NULL; + uint32_t remaining; + + *_r = NULL; + + r = talloc_zero(mem_ctx, struct dcerpc_sec_verification_trailer); + if (r == NULL) { + return NDR_ERR_ALLOC; + } + + if (ndr->data_size < sizeof(DCERPC_SEC_VT_MAGIC)) { + /* + * we return with r->count = 0 + */ + *_r = r; + return NDR_ERR_SUCCESS; + } + + ofs = ndr->data_size - sizeof(DCERPC_SEC_VT_MAGIC); + /* the magic is 4 byte aligned */ + ofs &= ~3; + + if (ofs > DCERPC_SEC_VT_MAX_SIZE) { + /* + * We just scan the last 1024 bytes. + */ + min_ofs = ofs - DCERPC_SEC_VT_MAX_SIZE; + } else { + min_ofs = 0; + } + + while (true) { + int ret; + + ret = memcmp(&ndr->data[ofs], + DCERPC_SEC_VT_MAGIC, + sizeof(DCERPC_SEC_VT_MAGIC)); + if (ret == 0) { + sub_blob = data_blob_const(&ndr->data[ofs], + ndr->data_size - ofs); + break; + } + + if (ofs <= min_ofs) { + break; + } + + ofs -= 4; + } + + if (sub_blob.length == 0) { + /* + * we return with r->count = 0 + */ + *_r = r; + return NDR_ERR_SUCCESS; + } + + sub_ndr = ndr_pull_init_blob(&sub_blob, r); + if (sub_ndr == NULL) { + TALLOC_FREE(r); + return NDR_ERR_ALLOC; + } + + ndr_err = ndr_pull_dcerpc_sec_verification_trailer(sub_ndr, + NDR_SCALARS | NDR_BUFFERS, + r); + if (ndr_err == NDR_ERR_ALLOC) { + TALLOC_FREE(r); + return NDR_ERR_ALLOC; + } + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto ignore_error; + } + + remaining = sub_ndr->data_size - sub_ndr->offset; + if (remaining > 16) { + /* + * we expect not more than 16 byte of additional + * padding after the verification trailer. + */ + goto ignore_error; + } + + /* + * We assume that we got a real verification trailer. + * + * We remove it from the available stub data. + */ + ndr->data_size = ofs; + + TALLOC_FREE(sub_ndr); + + *_r = r; + return NDR_ERR_SUCCESS; + +ignore_error: + TALLOC_FREE(sub_ndr); + /* + * just ignore the error, it's likely + * that the magic we found belongs to + * the stub data. + * + * we return with r->count = 0 + */ + ZERO_STRUCTP(r); + *_r = r; + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_dcerpc.h b/librpc/ndr/ndr_dcerpc.h new file mode 100644 index 0000000..d4ff927 --- /dev/null +++ b/librpc/ndr/ndr_dcerpc.h @@ -0,0 +1,29 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in the DCERPC protocol + + Copyright (C) Stefan Metzmacher 2014 + Copyright (C) Gregor Beck 2014 + + 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 . +*/ + +enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer( + struct ndr_pull *ndr, TALLOC_CTX *mem_ctx, + struct dcerpc_sec_verification_trailer **_r); + +#ifndef NDR_DCERPC_REQUEST_OBJECT_PRESENT +#define NDR_DCERPC_REQUEST_OBJECT_PRESENT (!!(ndr->flags & LIBNDR_FLAG_OBJECT_PRESENT)) +#endif /* NDR_DCERPC_REQUEST_OBJECT_PRESENT */ diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c new file mode 100644 index 0000000..9cc54c1 --- /dev/null +++ b/librpc/ndr/ndr_dns.c @@ -0,0 +1,327 @@ +/* + Unix SMB/CIFS implementation. + + manipulate dns name structures + + Copyright (C) 2010 Kai Blin + + Heavily based on nbtname.c which is: + + Copyright (C) Andrew Tridgell 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 . +*/ + +/* + see rfc1002 for the detailed format of compressed names +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dns.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_dnsp.h" +#include "system/locale.h" +#include "lib/util/util_net.h" +#include "ndr_dns_utils.h" + +/* don't allow an unlimited number of name components */ +#define MAX_COMPONENTS 128 + +/** + print a dns string +*/ +_PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr, + const char *name, + const char *s) +{ + ndr_print_string(ndr, name, s); +} + +/* + pull one component of a dns_string +*/ +static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr, + uint8_t **component, + uint32_t *offset, + uint32_t *max_offset) +{ + uint8_t len; + unsigned int loops = 0; + while (loops < 5) { + if (*offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component, bad offset"); + } + len = ndr->data[*offset]; + if (len == 0) { + *offset += 1; + *max_offset = MAX(*max_offset, *offset); + *component = NULL; + return NDR_ERR_SUCCESS; + } + if ((len & 0xC0) == 0xC0) { + /* its a label pointer */ + if (1 + *offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component, " \ + "bad label offset"); + } + *max_offset = MAX(*max_offset, *offset + 2); + *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset]; + *max_offset = MAX(*max_offset, *offset); + loops++; + continue; + } + if ((len & 0xC0) != 0) { + /* its a reserved length field */ + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component, " \ + "reserved length field: 0x%02"PRIx8, + (len &0xC)); + } + if (*offset + len + 1 > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component, "\ + "length too long"); + } + *component = (uint8_t*)talloc_strndup(ndr, + (const char *)&ndr->data[1 + *offset], len); + NDR_ERR_HAVE_NO_MEMORY(*component); + *offset += len + 1; + *max_offset = MAX(*max_offset, *offset); + return NDR_ERR_SUCCESS; + } + + /* too many pointers */ + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME component, too many pointers"); +} + +/** + pull a dns_string from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + const char **s) +{ + uint32_t offset = ndr->offset; + uint32_t max_offset = offset; + unsigned num_components; + char *name; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + name = talloc_strdup(ndr->current_mem_ctx, ""); + + /* break up name into a list of components */ + for (num_components=0; num_components 0) { + name = talloc_asprintf_append_buffer(name, ".%s", + component); + } else { + name = talloc_asprintf_append_buffer(name, "%s", + component); + } + NDR_ERR_HAVE_NO_MEMORY(name); + } + if (num_components == MAX_COMPONENTS) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD DNS NAME too many components"); + } + + (*s) = name; + ndr->offset = max_offset; + + return NDR_ERR_SUCCESS; +} + +/** + push a dns string to the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const char *s) +{ + return ndr_push_dns_string_list(ndr, + &ndr->dns_string_list, + ndr_flags, + s, + false); +} + +_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dns_txt_record *r) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + enum ndr_err_code ndr_err; + uint32_t data_size = ndr->data_size; + uint32_t record_size = 0; + ndr_err = ndr_token_retrieve(&ndr->array_size_list, r, + &record_size); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PULL_NEED_BYTES(ndr, record_size); + ndr->data_size = ndr->offset + record_size; + } + NDR_CHECK(ndr_pull_align(ndr, 1)); + NDR_CHECK(ndr_pull_dnsp_string_list(ndr, NDR_SCALARS, &r->txt)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 1)); + ndr->data_size = data_size; + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct dns_res_rec *r) +{ + libndr_flags _flags_save_STRUCT = ndr->flags; + uint32_t _saved_offset1, _saved_offset2; + uint16_t length; + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX | + LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + libndr_flags _flags_save_name = ndr->flags; + + NDR_CHECK(ndr_push_align(ndr, 4)); + + switch (r->rr_type) { + case DNS_QTYPE_TKEY: + case DNS_QTYPE_TSIG: + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_COMPRESSION); + break; + default: + break; + } + NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name)); + ndr->flags = _flags_save_name; + + NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type)); + NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl)); + _saved_offset1 = ndr->offset; + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0)); + if (r->length > 0) { + uint32_t _saved_offset3; + + NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, + r->rr_type)); + _saved_offset3 = ndr->offset; + NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS, + &r->rdata)); + if ((ndr->offset != _saved_offset3) && + (r->unexpected.length > 0)) { + /* + * ndr_push_dns_rdata pushed a known + * record, but we have something + * unexpected. That's invalid. + */ + return ndr_push_error(ndr, + NDR_ERR_LENGTH, + "Invalid...Unexpected " \ + "blob length is too " \ + "large"); + } + } + if (r->unexpected.length > UINT16_MAX) { + return ndr_push_error(ndr, NDR_ERR_LENGTH, + "Unexpected blob length "\ + "is too large"); + } + + NDR_CHECK(ndr_push_bytes(ndr, r->unexpected.data, + r->unexpected.length)); + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + length = ndr->offset - (_saved_offset1 + 2); + _saved_offset2 = ndr->offset; + ndr->offset = _saved_offset1; + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, length)); + ndr->offset = _saved_offset2; + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_BUFFERS, + &r->rdata)); + } + ndr->flags = _flags_save_STRUCT; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct dns_res_rec *r) +{ + libndr_flags _flags_save_STRUCT = ndr->flags; + uint32_t _saved_offset1; + uint32_t pad, length; + + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX | + LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name)); + NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type)); + NDR_CHECK(ndr_pull_dns_qclass(ndr, NDR_SCALARS, &r->rr_class)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length)); + _saved_offset1 = ndr->offset; + if (r->length > 0) { + NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list, + &r->rdata, + r->length)); + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata, + r->rr_type)); + NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS, + &r->rdata)); + } else { + ZERO_STRUCT(r->rdata); + } + length = ndr->offset - _saved_offset1; + if (length > r->length) { + return ndr_pull_error(ndr, NDR_ERR_LENGTH, "TODO"); + } + + r->unexpected = data_blob_null; + pad = r->length - length; + if (pad > 0) { + NDR_PULL_NEED_BYTES(ndr, pad); + r->unexpected = data_blob_talloc(ndr->current_mem_ctx, + ndr->data + + ndr->offset, + pad); + if (r->unexpected.data == NULL) { + return ndr_pull_error(ndr, + NDR_ERR_ALLOC, + "Failed to allocate a " \ + "data blob"); + } + ndr->offset += pad; + } + + + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_BUFFERS, &r->rdata)); + } + ndr->flags = _flags_save_STRUCT; + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_dns.h b/librpc/ndr/ndr_dns.h new file mode 100644 index 0000000..15617eb --- /dev/null +++ b/librpc/ndr/ndr_dns.h @@ -0,0 +1,40 @@ +/* + Unix SMB/CIFS implementation. + + manipulate dns name structures + + Copyright (C) 2010 Kai Blin + + Heavily based on nbtname.c which is: + + Copyright (C) Andrew Tridgell 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 . +*/ + +void ndr_print_dns_string(struct ndr_print *ndr, + const char *name, + const char *s); +enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + const char **s); +enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const char *s); +enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct dns_res_rec *r); +enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct dns_res_rec *r); diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c new file mode 100644 index 0000000..a2e0464 --- /dev/null +++ b/librpc/ndr/ndr_dns_utils.c @@ -0,0 +1,134 @@ +#include "includes.h" +#include "../librpc/ndr/libndr.h" +#include "ndr_dns_utils.h" + + +/** + push a dns/nbt string list to the wire +*/ +enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr, + struct ndr_token_list *string_list, + ndr_flags_type ndr_flags, + const char *s, + bool is_nbt) +{ + const char *start = s; + bool use_compression; + size_t max_length; + if (is_nbt) { + use_compression = true; + /* + * Max length is longer in NBT/Wins, because Windows counts + * the semi-decompressed size of the netbios name (16 bytes) + * rather than the wire size of 32, which is what you'd expect + * if it followed RFC1002 (it uses the short form in + * [MS-WINSRA]). In other words the maximum size of the + * "scope" is 237, not 221. + * + * We make the size limit slightly larger than 255 + 16, + * because the 237 scope limit is already enforced in the + * winsserver code with a specific return value; bailing out + * here would muck with that. + */ + max_length = 274; + } else { + use_compression = !(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION); + max_length = 255; + } + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + while (s && *s) { + enum ndr_err_code ndr_err; + char *compname; + size_t complen; + uint32_t offset; + + if (use_compression) { + /* see if we have pushed the remaining string already, + * if so we use a label pointer to this string + */ + ndr_err = ndr_token_retrieve_cmp_fn(string_list, s, + &offset, + (comparison_fn_t)strcmp, + false); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + uint8_t b[2]; + + if (offset > 0x3FFF) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "offset for dns string " \ + "label pointer " \ + "%"PRIu32"[%08"PRIX32"] > 0x00003FFF", + offset, offset); + } + + b[0] = 0xC0 | (offset>>8); + b[1] = (offset & 0xFF); + + return ndr_push_bytes(ndr, b, 2); + } + } + + complen = strcspn(s, "."); + + /* the length must fit into 6 bits (i.e. <= 63) */ + if (complen > 0x3F) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "component length %zu[%08zX] > " \ + "0x0000003F", + complen, + complen); + } + + if (complen == 0 && s[complen] == '.') { + return ndr_push_error(ndr, NDR_ERR_STRING, + "component length is 0 " + "(consecutive dots)"); + } + + if (is_nbt && s[complen] == '.' && s[complen + 1] == '\0') { + /* nbt names are sometimes usernames, and we need to + * keep a trailing dot to ensure it is byte-identical, + * (not just semantically identical given DNS + * semantics). */ + complen++; + } + + compname = talloc_asprintf(ndr, "%c%*.*s", + (unsigned char)complen, + (unsigned char)complen, + (unsigned char)complen, s); + NDR_ERR_HAVE_NO_MEMORY(compname); + + /* remember the current component + the rest of the string + * so it can be reused later + */ + if (use_compression) { + NDR_CHECK(ndr_token_store(ndr, string_list, s, + ndr->offset)); + } + + /* push just this component into the blob */ + NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, + complen+1)); + talloc_free(compname); + + s += complen; + if (*s == '.') { + s++; + } + if (s - start > max_length) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "name > %zu characters long", + max_length); + } + } + + /* if we reach the end of the string and have pushed the last component + * without using a label pointer, we need to terminate the string + */ + return ndr_push_bytes(ndr, (const uint8_t *)"", 1); +} diff --git a/librpc/ndr/ndr_dns_utils.h b/librpc/ndr/ndr_dns_utils.h new file mode 100644 index 0000000..b07496f --- /dev/null +++ b/librpc/ndr/ndr_dns_utils.h @@ -0,0 +1,6 @@ + +enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr, + struct ndr_token_list *string_list, + ndr_flags_type ndr_flags, + const char *s, + bool is_nbt); diff --git a/librpc/ndr/ndr_dnsp.c b/librpc/ndr/ndr_dnsp.c new file mode 100644 index 0000000..b4cad86 --- /dev/null +++ b/librpc/ndr/ndr_dnsp.c @@ -0,0 +1,263 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in DNSP + + Copyright (C) Andrew Tridgell 2010 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dnsp.h" + +/* + print a dnsp_name +*/ +_PUBLIC_ void ndr_print_dnsp_name(struct ndr_print *ndr, const char *name, + const char *dns_name) +{ + ndr->print(ndr, "%-25s: %s", name, dns_name); +} + +/* + pull a dnsp_name +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **name) +{ + uint8_t len, count, termination; + int i; + uint32_t total_len, raw_offset; + char *ret; + + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &len)); + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &count)); + + raw_offset = ndr->offset; + + ret = talloc_strdup(ndr->current_mem_ctx, ""); + if (!ret) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name"); + } + total_len = 1; + + for (i=0; icurrent_mem_ctx, ret, char, newlen); + if (!ret) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name"); + } + NDR_CHECK(ndr_pull_bytes(ndr, (uint8_t *)&ret[total_len-1], sublen)); + if (i != count-1) { + ret[newlen-2] = '.'; + } + ret[newlen-1] = 0; + total_len = newlen; + } + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &termination)); + if (termination != 0) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name - not NUL terminated"); + } + if (ndr->offset > raw_offset + len) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name - overrun by %"PRIu32" bytes", + ndr->offset - (raw_offset + len)); + } + /* there could be additional pad bytes */ + while (ndr->offset < raw_offset + len) { + uint8_t pad; + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &pad)); + } + (*name) = ret; + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_dnsp_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *name) +{ + int count, total_len, i; + + /* count the dots */ + for (count=i=0; name[i]; i++) { + if (name[i] == '.') count++; + } + total_len = strlen(name) + 1; + + /* + * cope with names ending in '.' + */ + if (name[0] == '\0') { + /* + * Don't access name[-1] for the "" input, which has + * the same meaning as a lone '.'. + * + * This allows a round-trip of a dnsRecord from + * Windows of a MX record of '.' + */ + } else if (name[strlen(name)-1] != '.') { + total_len++; + count++; + } + if (total_len > 255 || count > 255) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "dns_name of length %d larger than 255", total_len); + } + NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)total_len)); + NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)count)); + for (i=0; iprint(ndr, "%-25s: %s", name, dns_string); +} + +/* + pull a dnsp_string +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **string) +{ + uint8_t len; + char *ret; + + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &len)); + + ret = talloc_zero_array(ndr->current_mem_ctx, char, len + 1); + if (!ret) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string"); + } + NDR_CHECK(ndr_pull_bytes(ndr, (uint8_t *)ret, len)); + + (*string) = ret; + NDR_PULL_ALIGN(ndr, 1); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_dnsp_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *string) +{ + int total_len; + total_len = strlen(string); + if (total_len > 255) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "dns_name of length %d larger than 255", total_len); + } + NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)total_len)); + NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)string, total_len)); + + return NDR_ERR_SUCCESS; +} + +/* + * print a dnsp_string_list + */ +_PUBLIC_ void ndr_print_dnsp_string_list(struct ndr_print *ndr, const char *name, + const struct dnsp_string_list *list) +{ + uint32_t i; + + ndr->no_newline = true; + for (i=0; idepth; i++) { + ndr->print(ndr, " "); + } + ndr->print(ndr, "%-25s:", name); + for (i=0; icount; i++) { + ndr->print(ndr, " \"%s\"", list->str[i]); + } + ndr->print(ndr, "\n"); + ndr->no_newline = false; +} + +/* + * pull a dnsp_string_list + */ +_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_string_list(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dnsp_string_list *list) +{ + list->count = 0; + list->str = talloc_array(ndr->current_mem_ctx, const char *, + list->count); + if (! list->str) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string_list"); + } + + while (ndr->offset < ndr->data_size) { + list->str = talloc_realloc(ndr->current_mem_ctx, list->str, + const char *, list->count+1); + if (! list->str) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string_list"); + } + NDR_CHECK(ndr_pull_dnsp_string(ndr, ndr_flags, &list->str[list->count])); + list->count++; + } + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_dnsp_string_list(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dnsp_string_list *list) +{ + uint8_t i; + + for (i=0; icount; i++) { + NDR_CHECK(ndr_push_dnsp_string(ndr, ndr_flags, list->str[i])); + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_dnsp_string_list_copy(TALLOC_CTX *mem_ctx, + const struct dnsp_string_list *src, + struct dnsp_string_list *dst) +{ + size_t i; + + dst->count = 0; + dst->str = talloc_zero_array(mem_ctx, const char *, src->count); + if (dst->str == NULL) { + return NDR_ERR_ALLOC; + } + + for (i = 0; i < src->count; i++) { + dst->str[i] = talloc_strdup(dst->str, src->str[i]); + if (dst->str[i] == NULL) { + TALLOC_FREE(dst->str); + return NDR_ERR_ALLOC; + } + } + + dst->count = src->count; + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_dnsp.h b/librpc/ndr/ndr_dnsp.h new file mode 100644 index 0000000..1f68f29 --- /dev/null +++ b/librpc/ndr/ndr_dnsp.h @@ -0,0 +1,33 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in the DNSP IDL + + Copyright (C) Andrew Tridgell 2010 + + 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 . +*/ + +void ndr_print_dnsp_name(struct ndr_print *ndr, const char *name, + const char *dns_name); +enum ndr_err_code ndr_pull_dnsp_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **name); +enum ndr_err_code ndr_push_dnsp_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *name); +void ndr_print_dnsp_string(struct ndr_print *ndr, const char *name, + const char *dns_string); +enum ndr_err_code ndr_pull_dnsp_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **string); +enum ndr_err_code ndr_push_dnsp_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *string); + +enum ndr_err_code ndr_dnsp_string_list_copy(TALLOC_CTX *mem_ctx, + const struct dnsp_string_list *src, + struct dnsp_string_list *dst); diff --git a/librpc/ndr/ndr_dnsserver.c b/librpc/ndr/ndr_dnsserver.c new file mode 100644 index 0000000..814a366 --- /dev/null +++ b/librpc/ndr/ndr_dnsserver.c @@ -0,0 +1,100 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures for DNSSERVER + + Copyright (C) Amitay Isaacs 2011 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_dnsp.h" +#include "librpc/gen_ndr/ndr_dnsserver.h" + +/* + * parsing DNS_RPC_RECORDS_ARRAY + */ + +enum ndr_err_code ndr_pull_DNS_RPC_RECORDS_ARRAY(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, struct DNS_RPC_RECORDS_ARRAY *rec) +{ + rec->count = 0; + rec->rec = talloc_array(ndr->current_mem_ctx, struct DNS_RPC_RECORDS, rec->count); + if (! rec->rec) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORDS_ARRAY"); + } + + while (ndr->offset < ndr->data_size) { + rec->rec = talloc_realloc(ndr->current_mem_ctx, rec->rec, struct DNS_RPC_RECORDS, rec->count+1); + if (! rec->rec) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORDS_ARRAY"); + } + NDR_CHECK(ndr_pull_DNS_RPC_RECORDS(ndr, ndr_flags, &rec->rec[rec->count])); + NDR_PULL_ALIGN(ndr, 4); + rec->count++; + } + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_DNS_RPC_RECORDS_ARRAY(struct ndr_push *ndr, + ndr_flags_type ndr_flags, const struct DNS_RPC_RECORDS_ARRAY *rec) +{ + int i; + + for (i=0; icount; i++) { + NDR_CHECK(ndr_push_DNS_RPC_RECORDS(ndr, ndr_flags, &rec->rec[i])); + NDR_PUSH_ALIGN(ndr, 4); + } + + return NDR_ERR_SUCCESS; +} + +/* + * Parsing of DNS_RPC_RECORD_STRING + */ + +enum ndr_err_code ndr_pull_DNS_RPC_RECORD_STRING(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, struct DNS_RPC_RECORD_STRING *rec) +{ + rec->count = 0; + rec->str = talloc_array(ndr->current_mem_ctx, struct DNS_RPC_NAME, rec->count); + if (! rec->str) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORD_STRING"); + } + + while (ndr->offset < ndr->data_size) { + rec->str = talloc_realloc(ndr->current_mem_ctx, rec->str, struct DNS_RPC_NAME, rec->count+1); + if (! rec->str) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORD_STRING"); + } + NDR_CHECK(ndr_pull_DNS_RPC_NAME(ndr, ndr_flags, &rec->str[rec->count])); + rec->count++; + } + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_DNS_RPC_RECORD_STRING(struct ndr_push *ndr, + ndr_flags_type ndr_flags, const struct DNS_RPC_RECORD_STRING *rec) +{ + int i; + + for (i=0; icount; i++) { + NDR_CHECK(ndr_push_DNS_RPC_NAME(ndr, ndr_flags, &rec->str[i])); + } + + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_dnsserver.h b/librpc/ndr/ndr_dnsserver.h new file mode 100644 index 0000000..04eb220 --- /dev/null +++ b/librpc/ndr/ndr_dnsserver.h @@ -0,0 +1,25 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures for DNSSERVER + + Copyright (C) Amitay Isaacs 2011 + + 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 . +*/ + +enum ndr_err_code ndr_pull_DNS_RPC_RECORDS_ARRAY(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, struct DNS_RPC_RECORDS_ARRAY *rec); +enum ndr_err_code ndr_push_DNS_RPC_RECORDS_ARRAY(struct ndr_push *ndr, + ndr_flags_type ndr_flags, const struct DNS_RPC_RECORDS_ARRAY *rec); diff --git a/librpc/ndr/ndr_drsblobs.c b/librpc/ndr/ndr_drsblobs.c new file mode 100644 index 0000000..b6eea17 --- /dev/null +++ b/librpc/ndr/ndr_drsblobs.c @@ -0,0 +1,220 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in the DRS protocol + + Copyright (C) Andrew Bartlett 2008 + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "../lib/util/asn1.h" + +_PUBLIC_ enum ndr_err_code ndr_push_AuthenticationInformationArray(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AuthenticationInformationArray *r) +{ + uint32_t cntr_array_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) { + NDR_CHECK(ndr_push_AuthenticationInformation(ndr, NDR_SCALARS, &r->array[cntr_array_0])); + } + NDR_CHECK(ndr_push_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_AuthenticationInformationArray(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AuthenticationInformationArray *r) +{ + if (ndr_flags & NDR_SCALARS) { + r->count = 0; + NDR_PULL_ALLOC_N(ndr, r->array, r->count); + /* entry is at least 16 bytes large */ + while (ndr->offset + 16 <= ndr->data_size) { + r->array = talloc_realloc(ndr, r->array, struct AuthenticationInformation, r->count + 1); + NDR_ERR_HAVE_NO_MEMORY(r->array); + NDR_CHECK(ndr_pull_AuthenticationInformation(ndr, NDR_SCALARS, &r->array[r->count])); + r->count++; + } + NDR_CHECK(ndr_pull_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_trustAuthInOutBlob(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct trustAuthInOutBlob *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->count > 0)?12:0)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0)); + { + struct ndr_push *_ndr_current; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_current, 0, ((r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0) - ((r->count > 0)?12:0))); + NDR_CHECK(ndr_push_AuthenticationInformationArray(_ndr_current, NDR_SCALARS, &r->current)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_current, 0, ((r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0) - ((r->count > 0)?12:0))); + } + { + libndr_flags _flags_save_AuthenticationInformationArray = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING); + { + struct ndr_push *_ndr_previous; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_previous, 0, -1)); + NDR_CHECK(ndr_push_AuthenticationInformationArray(_ndr_previous, NDR_SCALARS, &r->previous)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_previous, 0, -1)); + } + ndr->flags = _flags_save_AuthenticationInformationArray; + } + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + + +_PUBLIC_ enum ndr_err_code ndr_pull_trustDomainPasswords(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct trustDomainPasswords *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t offset; + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + + offset = ndr->offset; + ndr->offset = ndr->data_size - 8; + + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->outgoing_size)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->incoming_size)); + + ndr->offset = offset; + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->confounder, 512)); + { + struct ndr_pull *_ndr_outgoing; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_outgoing, 0, r->outgoing_size)); + NDR_CHECK(ndr_pull_trustAuthInOutBlob(_ndr_outgoing, NDR_SCALARS|NDR_BUFFERS, &r->outgoing)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_outgoing, 0, r->outgoing_size)); + } + { + struct ndr_pull *_ndr_incoming; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_incoming, 0, r->incoming_size)); + NDR_CHECK(ndr_pull_trustAuthInOutBlob(_ndr_incoming, NDR_SCALARS|NDR_BUFFERS, &r->incoming)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_incoming, 0, r->incoming_size)); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->outgoing_size)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->incoming_size)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_drsuapi_MSPrefixMap_Entry(struct ndr_print *ndr, const char *name, const struct drsuapi_MSPrefixMap_Entry *r) +{ + ndr_print_struct(ndr, name, "drsuapi_MSPrefixMap_Entry"); + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + ndr->depth++; + ndr_print_uint16(ndr, "entryID", r->entryID); + ndr->print(ndr, "%-25s: length=%"PRIu16, "oid", r->length); + if (r->binary_oid) { + char *partial_oid = NULL; + DATA_BLOB oid_blob = data_blob_const(r->binary_oid, r->length); + char *hex_str = data_blob_hex_string_upper(ndr, &oid_blob); + ber_read_partial_OID_String(ndr, oid_blob, &partial_oid); + ndr->depth++; + ndr->print(ndr, "%-25s: 0x%s (%s)", "binary_oid", hex_str, partial_oid); + ndr->depth--; + talloc_free(hex_str); + talloc_free(partial_oid); + } + ndr->depth--; + ndr->flags = _flags_save_STRUCT; + } +} + +_PUBLIC_ enum ndr_err_code ndr_push_supplementalCredentialsSubBlob(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct supplementalCredentialsSubBlob *r) +{ + uint32_t cntr_packages_0; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + if ((r->signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) + && (r->num_packages == 0)) { + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_align(ndr, 3)); + NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_PREFIX, 0x30, sizeof(uint16_t), CH_UTF16)); + NDR_CHECK(ndr_push_supplementalCredentialsSignature(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_SIGNATURE)); + if (r->num_packages > 0) { + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_packages)); + } + for (cntr_packages_0 = 0; cntr_packages_0 < (r->num_packages); cntr_packages_0++) { + NDR_CHECK(ndr_push_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0])); + } + NDR_CHECK(ndr_push_trailer_align(ndr, 3)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_supplementalCredentialsSubBlob(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct supplementalCredentialsSubBlob *r) +{ + uint32_t size_prefix_0 = 0; + uint32_t size_packages_0 = 0; + uint32_t cntr_packages_0; + TALLOC_CTX *_mem_save_packages_0 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + uint32_t remaining = 0; + NDR_CHECK(ndr_pull_align(ndr, 3)); + size_prefix_0 = 0x30; + remaining = ndr->data_size - ndr->offset; + if (remaining >= size_prefix_0) { + NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->prefix, size_prefix_0, sizeof(uint16_t), CH_UTF16)); + } else { + r->prefix = NULL; + } + remaining = ndr->data_size - ndr->offset; + if (remaining >= 2) { + NDR_CHECK(ndr_pull_supplementalCredentialsSignature(ndr, NDR_SCALARS, &r->signature)); + } else { + r->signature = 0; + } + remaining = ndr->data_size - ndr->offset; + if (remaining > 0) { + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_packages)); + } else { + r->num_packages = 0; + } + size_packages_0 = r->num_packages; + NDR_PULL_ALLOC_N(ndr, r->packages, size_packages_0); + _mem_save_packages_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->packages, 0); + for (cntr_packages_0 = 0; cntr_packages_0 < (size_packages_0); cntr_packages_0++) { + NDR_CHECK(ndr_pull_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_packages_0, 0); + NDR_CHECK(ndr_pull_trailer_align(ndr, 3)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_drsblobs.h b/librpc/ndr/ndr_drsblobs.h new file mode 100644 index 0000000..d310808 --- /dev/null +++ b/librpc/ndr/ndr_drsblobs.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures found in the DRS protocol + + Copyright (C) Andrew Bartlett 2008 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_pull_trustDomainPasswords(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct trustDomainPasswords *r); +_PUBLIC_ void ndr_print_drsuapi_MSPrefixMap_Entry(struct ndr_print *ndr, const char *name, const struct drsuapi_MSPrefixMap_Entry *r); diff --git a/librpc/ndr/ndr_drsuapi.c b/librpc/ndr/ndr_drsuapi.c new file mode 100644 index 0000000..63d1d74 --- /dev/null +++ b/librpc/ndr/ndr_drsuapi.c @@ -0,0 +1,577 @@ +/* + Unix SMB/CIFS implementation. + + routines for printing some linked list structs in DRSUAPI + + Copyright (C) Stefan (metze) Metzmacher 2005 + Copyright (C) Matthieu Patou 2013 + + 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 . +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "../lib/util/asn1.h" +#include "librpc/ndr/ndr_compression.h" +/* We don't need multibyte if we're just comparing to 'ff' */ +#undef strncasecmp + +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); + } +} + +_PUBLIC_ void ndr_print_drsuapi_DsReplicaOID(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOID *r) +{ + ndr_print_struct(ndr, name, "drsuapi_DsReplicaOID"); + ndr->depth++; + ndr_print_uint32(ndr, "length", r->length); + ndr->print(ndr, "%-25s: length=%"PRIu32, "oid", r->length); + if (r->binary_oid) { + char *partial_oid = NULL; + DATA_BLOB oid_blob = data_blob_const(r->binary_oid, r->length); + char *hex_str = data_blob_hex_string_upper(ndr, &oid_blob); + ber_read_partial_OID_String(ndr, oid_blob, &partial_oid); + ndr->depth++; + ndr->print(ndr, "%-25s: 0x%s (%s)", "binary_oid", hex_str, partial_oid); + ndr->depth--; + talloc_free(hex_str); + talloc_free(partial_oid); + } + ndr->depth--; +} + +static void _print_drsuapi_DsAttributeValue_attid(struct ndr_print *ndr, const char *name, + const struct drsuapi_DsAttributeValue *r) +{ + uint32_t v; + + ndr_print_struct(ndr, name, "drsuapi_DsAttributeValue"); + ndr->depth++; + if (r->blob == NULL || r->blob->data == NULL) { + ndr_print_string(ndr, "attid", "NULL"); + } else if (r->blob->length < 4) { + ndr_print_DATA_BLOB(ndr, "attid", *r->blob); + } else { + v = IVAL(r->blob->data, 0); + ndr_print_uint32(ndr, "attid", v); + } + ndr->depth--; +} + +static void _print_drsuapi_DsAttributeValue_str(struct ndr_print *ndr, const char *name, + const struct drsuapi_DsAttributeValue *r) +{ + void *p; + size_t converted_size = 0; + + ndr_print_struct(ndr, name, "drsuapi_DsAttributeValue"); + ndr->depth++; + if (r->blob == NULL || r->blob->data == NULL) { + ndr_print_string(ndr, "string", "NULL"); + } else if (!convert_string_talloc(ndr, + CH_UTF16, CH_UNIX, + r->blob->data, + r->blob->length, + &p, &converted_size)) { + ndr_print_DATA_BLOB(ndr, "string (INVALID CONVERSION)", + *r->blob); + } else { + char *str = (char *)p; + ndr_print_string(ndr, "string", str); + talloc_free(str); + } + ndr->depth--; +} + +static void _print_drsuapi_DsAttributeValueCtr(struct ndr_print *ndr, + const char *name, + const struct drsuapi_DsAttributeValueCtr *r, + void (*print_val_fn)(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValue *r)) +{ + uint32_t cntr_values_1; + ndr_print_struct(ndr, name, "drsuapi_DsAttributeValueCtr"); + ndr->depth++; + ndr_print_uint32(ndr, "num_values", r->num_values); + ndr_print_ptr(ndr, "values", r->values); + ndr->depth++; + if (r->values) { + ndr->print(ndr, "%s: ARRAY(%"PRIu32")", "values", r->num_values); + ndr->depth++; + for (cntr_values_1=0;cntr_values_1num_values;cntr_values_1++) { + char *idx_1=NULL; + if (asprintf(&idx_1, "[%"PRIu32"]", cntr_values_1) != -1) { + //ndr_print_drsuapi_DsAttributeValue(ndr, "values", &r->values[cntr_values_1]); + print_val_fn(ndr, "values", &r->values[cntr_values_1]); + free(idx_1); + } + } + ndr->depth--; + } + ndr->depth--; + ndr->depth--; +} + +_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttribute(struct ndr_print *ndr, + const char *name, + const struct drsuapi_DsReplicaAttribute *r) +{ + ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttribute"); + ndr->depth++; + ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid); + switch (r->attid) { + case DRSUAPI_ATTID_objectClass: + case DRSUAPI_ATTID_possSuperiors: + case DRSUAPI_ATTID_subClassOf: + case DRSUAPI_ATTID_governsID: + case DRSUAPI_ATTID_mustContain: + case DRSUAPI_ATTID_mayContain: + case DRSUAPI_ATTID_rDNAttId: + case DRSUAPI_ATTID_attributeID: + case DRSUAPI_ATTID_attributeSyntax: + case DRSUAPI_ATTID_auxiliaryClass: + case DRSUAPI_ATTID_systemPossSuperiors: + case DRSUAPI_ATTID_systemMayContain: + case DRSUAPI_ATTID_systemMustContain: + case DRSUAPI_ATTID_systemAuxiliaryClass: + case DRSUAPI_ATTID_transportAddressAttribute: + /* ATTIDs for classSchema and attributeSchema */ + _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr, + _print_drsuapi_DsAttributeValue_attid); + break; + case DRSUAPI_ATTID_cn: + case DRSUAPI_ATTID_ou: + case DRSUAPI_ATTID_description: + case DRSUAPI_ATTID_displayName: + case DRSUAPI_ATTID_dMDLocation: + case DRSUAPI_ATTID_adminDisplayName: + case DRSUAPI_ATTID_adminDescription: + case DRSUAPI_ATTID_lDAPDisplayName: + case DRSUAPI_ATTID_name: + _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr, + _print_drsuapi_DsAttributeValue_str); + break; + default: + _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr, + ndr_print_drsuapi_DsAttributeValue); + break; + } + ndr->depth--; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2)); + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary_without_Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, libndr_flags flags) +{ + return ndr_size_struct((const struct drsuapi_DsReplicaObjectIdentifier3 *)r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3); +} + +_PUBLIC_ void ndr_print_drsuapi_SecBufferType(struct ndr_print *ndr, const char *name, enum drsuapi_SecBufferType r) +{ + const char *val = NULL; + + switch (r & 0x00000007) { + case DRSUAPI_SECBUFFER_EMPTY: val = "DRSUAPI_SECBUFFER_EMPTY"; break; + case DRSUAPI_SECBUFFER_DATA: val = "DRSUAPI_SECBUFFER_DATA"; break; + case DRSUAPI_SECBUFFER_TOKEN: val = "DRSUAPI_SECBUFFER_TOKEN"; break; + case DRSUAPI_SECBUFFER_PKG_PARAMS: val = "DRSUAPI_SECBUFFER_PKG_PARAMS"; break; + case DRSUAPI_SECBUFFER_MISSING: val = "DRSUAPI_SECBUFFER_MISSING"; break; + case DRSUAPI_SECBUFFER_EXTRA: val = "DRSUAPI_SECBUFFER_EXTRA"; break; + case DRSUAPI_SECBUFFER_STREAM_TRAILER: val = "DRSUAPI_SECBUFFER_STREAM_TRAILER"; break; + case DRSUAPI_SECBUFFER_STREAM_HEADER: val = "DRSUAPI_SECBUFFER_STREAM_HEADER"; break; + } + + if (r & DRSUAPI_SECBUFFER_READONLY) { + char *v = talloc_asprintf(ndr, "DRSUAPI_SECBUFFER_READONLY | %s", val); + ndr_print_enum(ndr, name, "ENUM", v, r); + } else { + ndr_print_enum(ndr, name, "ENUM", val, r); + } +} + +_PUBLIC_ void ndr_print_drsuapi_DsAddEntry_AttrErrListItem_V1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntry_AttrErrListItem_V1 *r) +{ + ndr_print_struct(ndr, name, "drsuapi_DsAddEntry_AttrErrListItem_V1"); + ndr->depth++; + ndr_print_ptr(ndr, "next", r->next); + ndr_print_drsuapi_DsAddEntry_AttrErr_V1(ndr, "err_data", &r->err_data); + ndr->depth--; + if (r->next) { + ndr_print_drsuapi_DsAddEntry_AttrErrListItem_V1(ndr, "next", r->next); + } +} + +enum ndr_err_code ndr_push_drsuapi_DsBindInfo(struct ndr_push *ndr, ndr_flags_type ndr_flags, const union drsuapi_DsBindInfo *r) +{ + libndr_flags _flags_save = ndr->flags; + ndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + uint32_t level; + NDR_CHECK(ndr_push_steal_switch_value(ndr, r, &level)); + NDR_CHECK(ndr_push_union_align(ndr, 4)); + switch (level) { + case 24: { + { + struct ndr_push *_ndr_info24; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info24, 0, 24)); + NDR_CHECK(ndr_push_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info24, 0, 24)); + } + break; } + + case 28: { + { + struct ndr_push *_ndr_info28; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info28, 0, 28)); + NDR_CHECK(ndr_push_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info28, 0, 28)); + } + break; } + + case 48: { + { + struct ndr_push *_ndr_info48; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info48, 0, 48)); + NDR_CHECK(ndr_push_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info48, 0, 48)); + } + break; } + + case 52: { + { + struct ndr_push *_ndr_info52; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info52, 0, 52)); + NDR_CHECK(ndr_push_drsuapi_DsBindInfo52(_ndr_info52, NDR_SCALARS, &r->info52)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info52, 0, 52)); + } + break; } + + default: { + { + struct ndr_push *_ndr_Fallback; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_Fallback, 0, level)); + NDR_CHECK(ndr_push_drsuapi_DsBindInfoFallBack(_ndr_Fallback, NDR_SCALARS, &r->Fallback)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_Fallback, 0, level)); + } + break; } + + } + } + ndr->flags = _flags_save; + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_drsuapi_DsBindInfo(struct ndr_pull *ndr, ndr_flags_type ndr_flags, union drsuapi_DsBindInfo *r) +{ + libndr_flags _flags_save = ndr->flags; + ndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + uint32_t level; + NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); + NDR_CHECK(ndr_pull_union_align(ndr, 4)); + switch (level) { + case 24: { + { + struct ndr_pull *_ndr_info24; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info24, 0, 24)); + NDR_CHECK(ndr_pull_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info24, 0, 24)); + } + break; } + + case 28: { + { + struct ndr_pull *_ndr_info28; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info28, 0, 28)); + NDR_CHECK(ndr_pull_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info28, 0, 28)); + } + break; } + + case 48: { + { + struct ndr_pull *_ndr_info48; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info48, 0, 48)); + NDR_CHECK(ndr_pull_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info48, 0, 48)); + } + break; } + + case 52: { + { + struct ndr_pull *_ndr_info52; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info52, 0, 52)); + NDR_CHECK(ndr_pull_drsuapi_DsBindInfo52(_ndr_info52, NDR_SCALARS, &r->info52)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info52, 0, 52)); + } + break; } + + default: { + { + struct ndr_pull *_ndr_Fallback; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_Fallback, 0, level)); + NDR_CHECK(ndr_pull_drsuapi_DsBindInfoFallBack(_ndr_Fallback, NDR_SCALARS, &r->Fallback)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_Fallback, 0, level)); + } + break; } + + } + } + ndr->flags = _flags_save; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_drsuapi_DsBindInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsBindInfo *r) +{ + uint32_t level; + level = ndr_print_steal_switch_value(ndr, r); + ndr_print_union(ndr, name, level, "drsuapi_DsBindInfo"); + switch (level) { + case 24: + ndr_print_drsuapi_DsBindInfo24(ndr, "info24", &r->info24); + break; + + case 28: + ndr_print_drsuapi_DsBindInfo28(ndr, "info28", &r->info28); + break; + + case 48: + ndr_print_drsuapi_DsBindInfo48(ndr, "info48", &r->info48); + break; + + case 52: + ndr_print_drsuapi_DsBindInfo52(ndr, "info52", &r->info52); + break; + + default: + ndr_print_drsuapi_DsBindInfoFallBack(ndr, "Fallback", &r->Fallback); + break; + + } +} diff --git a/librpc/ndr/ndr_drsuapi.h b/librpc/ndr/ndr_drsuapi.h new file mode 100644 index 0000000..6399a34 --- /dev/null +++ b/librpc/ndr/ndr_drsuapi.h @@ -0,0 +1,34 @@ +/* + 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 . +*/ + +#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); + +size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary_without_Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, libndr_flags flags); + + +#endif /* _LIBRPC_NDR_NDR_DRSUAPI_H */ diff --git a/librpc/ndr/ndr_frsrpc.c b/librpc/ndr/ndr_frsrpc.c new file mode 100644 index 0000000..78c00ed --- /dev/null +++ b/librpc/ndr/ndr_frsrpc.c @@ -0,0 +1,92 @@ +/* + Unix SMB/CIFS implementation. + + helper routines for FRSRPC marshalling + + Copyright (C) Stefan (metze) Metzmacher 2009 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_frsrpc.h" + +enum ndr_err_code ndr_push_frsrpc_CommPktChunkCtr(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct frsrpc_CommPktChunkCtr *r) +{ + uint32_t cntr_chunks_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 2)); + for (cntr_chunks_0 = 0; cntr_chunks_0 < r->num_chunks; cntr_chunks_0++) { + NDR_CHECK(ndr_push_frsrpc_CommPktChunk(ndr, NDR_SCALARS, &r->chunks[cntr_chunks_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +#define _TMP_PULL_REALLOC_N(ndr, s, t, n) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_realloc(ndr->current_mem_ctx, (s), t, n); \ + if (!(s)) { \ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ + "Alloc %u * %s failed: %s\n", \ + (unsigned)n, # s, __location__); \ + } \ +} while (0) + +enum ndr_err_code ndr_pull_frsrpc_CommPktChunkCtr(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct frsrpc_CommPktChunkCtr *r) +{ + uint32_t cntr_chunks_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + uint32_t remaining = ndr->data_size - ndr->offset; + r->num_chunks = 0; + r->chunks = NULL; + for (cntr_chunks_0 = 0; remaining > 0; cntr_chunks_0++) { + r->num_chunks += 1; + _TMP_PULL_REALLOC_N(ndr, r->chunks, + struct frsrpc_CommPktChunk, + r->num_chunks); + NDR_CHECK(ndr_pull_frsrpc_CommPktChunk(ndr, + NDR_SCALARS, + &r->chunks[cntr_chunks_0])); + remaining = ndr->data_size - ndr->offset; + } + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +size_t ndr_size_frsrpc_CommPktChunkCtr(const struct frsrpc_CommPktChunkCtr *r, + libndr_flags flags) +{ + flags |= LIBNDR_FLAG_NOALIGN; + return ndr_size_struct(r, flags, + (ndr_push_flags_fn_t)ndr_push_frsrpc_CommPktChunkCtr); +} diff --git a/librpc/ndr/ndr_frsrpc.h b/librpc/ndr/ndr_frsrpc.h new file mode 100644 index 0000000..afdfd66 --- /dev/null +++ b/librpc/ndr/ndr_frsrpc.h @@ -0,0 +1,34 @@ +/* + Unix SMB/CIFS implementation. + + helper routines for FRSRPC marshalling + + Copyright (C) Stefan (metze) Metzmacher 2009 + + 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 . +*/ + +#ifndef _LIBRPC_NDR_NDR_FRSRPC_H +#define _LIBRPC_NDR_NDR_FRSRPC_H + +enum ndr_err_code ndr_push_frsrpc_CommPktChunkCtr(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct frsrpc_CommPktChunkCtr *r); +enum ndr_err_code ndr_pull_frsrpc_CommPktChunkCtr(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct frsrpc_CommPktChunkCtr *r); +size_t ndr_size_frsrpc_CommPktChunkCtr(const struct frsrpc_CommPktChunkCtr *r, + libndr_flags flags); + +#endif /* _LIBRPC_NDR_NDR_FRSRPC_H */ diff --git a/librpc/ndr/ndr_ioctl.c b/librpc/ndr/ndr_ioctl.c new file mode 100644 index 0000000..7e76abc --- /dev/null +++ b/librpc/ndr/ndr_ioctl.c @@ -0,0 +1,40 @@ +/* + Unix SMB/CIFS implementation. + + Manually parsed structures for IOCTL/FSCTL + + Copyright (C) Stefan Metzmacher 2014 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_ioctl.h" + +_PUBLIC_ void ndr_print_fsctl_net_iface_info(struct ndr_print *ndr, const char *name, const struct fsctl_net_iface_info *r) +{ + ndr_print_struct(ndr, name, "fsctl_net_iface_info"); + if (r == NULL) { ndr_print_null(ndr); return; } + ndr->depth++; + ndr_print_ptr(ndr, "next", r->next); + ndr_print_uint32(ndr, "ifindex", r->ifindex); + ndr_print_fsctl_net_iface_capability(ndr, "capability", r->capability); + ndr_print_uint32(ndr, "reserved", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved); + ndr_print_hyper(ndr, "linkspeed", r->linkspeed); + ndr_print_fsctl_sockaddr_storage(ndr, "sockaddr", &r->sockaddr); + ndr->depth--; + if (r->next) { + ndr_print_fsctl_net_iface_info(ndr, "next", r->next); + } +} diff --git a/librpc/ndr/ndr_krb5pac.c b/librpc/ndr/ndr_krb5pac.c new file mode 100644 index 0000000..60eacd3 --- /dev/null +++ b/librpc/ndr/ndr_krb5pac.c @@ -0,0 +1,130 @@ +/* + 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 . +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_krb5pac.h" + +size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, libndr_flags flags) +{ + size_t s = ndr_size_PAC_INFO(r, level, flags); + switch (level) { + case PAC_TYPE_LOGON_INFO: + return NDR_ROUND(s,8); + case PAC_TYPE_UPN_DNS_INFO: + return NDR_ROUND(s,8); + default: + return s; + } +} + +enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, ndr_flags_type 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,LIBNDR_FLAG_ALIGN8))); + { + libndr_flags _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) { + { + libndr_flags _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); + if (r->info) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->info)); + { + struct ndr_push *_ndr_info_pad; + struct ndr_push *_ndr_info; + size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8); + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8))); + NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size)); + 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_info_pad, _ndr_info, 0, _ndr_size)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8))); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->info)); + } + ndr->flags = _flags_save_PAC_INFO; + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, ndr_flags_type 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)); + { + libndr_flags _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) { + { + libndr_flags _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_pad; + struct ndr_pull *_ndr_info; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(r->_ndr_size, 8))); + NDR_CHECK(ndr_pull_subcontext_start(_ndr_info_pad, &_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_info_pad, _ndr_info, 0, r->_ndr_size)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info_pad, 0, NDR_ROUND(r->_ndr_size, 8))); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_PAC_INFO; + } + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_krb5pac.h b/librpc/ndr/ndr_krb5pac.h new file mode 100644 index 0000000..e009133 --- /dev/null +++ b/librpc/ndr/ndr_krb5pac.h @@ -0,0 +1,25 @@ +/* + 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 . +*/ + + +#include "librpc/gen_ndr/ndr_krb5pac.h" + +size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, libndr_flags flags); diff --git a/librpc/ndr/ndr_misc.c b/librpc/ndr/ndr_misc.c new file mode 100644 index 0000000..de8dcb4 --- /dev/null +++ b/librpc/ndr/ndr_misc.c @@ -0,0 +1,77 @@ +/* + Unix SMB/CIFS implementation. + + UUID/GUID/policy_handle functions + + 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 . +*/ + +#include "includes.h" +#include "system/network.h" +#include "librpc/ndr/libndr.h" +#include "libcli/util/ntstatus.h" +#include "lib/util/util_str_hex.h" + +_PUBLIC_ void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid) +{ + struct GUID_txt_buf buf; + ndr->print(ndr, "%-25s: %s", name, GUID_buf_string(guid, &buf)); +} + +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); +} + +char *ndr_syntax_id_buf_string( + const struct ndr_syntax_id *id, struct ndr_syntax_id_buf *dst) +{ + struct GUID_txt_buf guid_buf; + + snprintf(dst->buf, + sizeof(dst->buf), + "%s/0x%08"PRIx32, + GUID_buf_string(&id->uuid, &guid_buf), + id->if_version); + + return dst->buf; +} + +_PUBLIC_ char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id) +{ + struct ndr_syntax_id_buf buf; + return talloc_strdup(mem_ctx, ndr_syntax_id_buf_string(id, &buf)); +} + +_PUBLIC_ bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id) +{ + bool ok; + + ok = parse_guid_string(s, &id->uuid); + if (!ok) { + return false; + } + + if (strncmp(s + 36, "/0x", 3) != 0) { + return false; + } + + ok = hex_uint32(s+39, &id->if_version); + return ok; +} diff --git a/librpc/ndr/ndr_nbt.c b/librpc/ndr/ndr_nbt.c new file mode 100644 index 0000000..6f54198 --- /dev/null +++ b/librpc/ndr/ndr_nbt.c @@ -0,0 +1,406 @@ +/* + Unix SMB/CIFS implementation. + + CLDAP server structures + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Andrew Bartlett 2008 + + 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 . +*/ + +/* parser auto-generated by pidl, then hand-modified by abartlet */ + +#include "includes.h" +#include "../libcli/nbt/libnbt.h" +#include "../libcli/netlogon/netlogon.h" +#include "ndr_dns_utils.h" + + +/* don't allow an unlimited number of name components */ +#define MAX_COMPONENTS 128 + +/** + print a nbt string +*/ +_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s) +{ + ndr_print_string(ndr, name, s); +} + +/* + pull one component of a nbt_string +*/ +static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr, + uint8_t **component, + uint32_t *offset, + uint32_t *max_offset) +{ + uint8_t len; + unsigned int loops = 0; + while (loops < 5) { + if (*offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD NBT NAME component"); + } + len = ndr->data[*offset]; + if (len == 0) { + *offset += 1; + *max_offset = MAX(*max_offset, *offset); + *component = NULL; + return NDR_ERR_SUCCESS; + } + if ((len & 0xC0) == 0xC0) { + /* its a label pointer */ + if (1 + *offset >= ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD NBT NAME component"); + } + *max_offset = MAX(*max_offset, *offset + 2); + *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset]; + *max_offset = MAX(*max_offset, *offset); + loops++; + continue; + } + if ((len & 0xC0) != 0) { + /* its a reserved length field */ + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD NBT NAME component"); + } + if (*offset + len + 1 > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "BAD NBT NAME component"); + } + *component = (uint8_t*)talloc_strndup( + ndr->current_mem_ctx, + (const char *)&ndr->data[1 + *offset], len); + NDR_ERR_HAVE_NO_MEMORY(*component); + *offset += len + 1; + *max_offset = MAX(*max_offset, *offset); + return NDR_ERR_SUCCESS; + } + + /* too many pointers */ + return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component"); +} + +/** + pull a nbt_string from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **s) +{ + uint32_t offset = ndr->offset; + uint32_t max_offset = offset; + unsigned num_components; + char *name; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + name = NULL; + + /* break up name into a list of components */ + for (num_components=0;num_componentscurrent_mem_ctx, ""); + NDR_ERR_HAVE_NO_MEMORY(name); + } + + (*s) = name; + ndr->offset = max_offset; + + return NDR_ERR_SUCCESS; +} + +/** + push a nbt string to the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *s) +{ + return ndr_push_dns_string_list(ndr, + &ndr->dns_string_list, + ndr_flags, + s, + true); +} + + +/* Manually modified to handle the dom_sid being optional based on if it is present or all zero */ +enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_REQUEST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_REQUEST *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->request_count)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acct_control)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid0(&r->sid, ndr->flags))); + if (ndr_size_dom_sid0(&r->sid, ndr->flags)) { + struct ndr_push *_ndr_sid; + libndr_flags _flags_save_DATA_BLOB = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad)); + ndr->flags = _flags_save_DATA_BLOB; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags))); + NDR_CHECK(ndr_push_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags))); + } + NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +/* Manually modified to handle the dom_sid being optional based on if it is present (size is non-zero) or not */ +enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_REQUEST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_REQUEST *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->request_count)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acct_control)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_size)); + if (r->sid_size) { + libndr_flags _flags_save_DATA_BLOB = ndr->flags; + struct ndr_pull *_ndr_sid; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad)); + ndr->flags = _flags_save_DATA_BLOB; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sid, 0, r->sid_size)); + NDR_CHECK(ndr_pull_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sid, 0, r->sid_size)); + } else { + ZERO_STRUCT(r->sid); + } + NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +/* Manually modified to only push some parts of the structure if certain flags are set */ +enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_RESPONSE_EX *r) +{ + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_netlogon_command(ndr, NDR_SCALARS, r->command)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz)); + NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type)); + NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain_name)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site)); + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site)); + if (r->nt_version & NETLOGON_NT_VERSION_5EX_WITH_IP) { + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags))); + { + struct ndr_push *_ndr_sockaddr; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags))); + NDR_CHECK(ndr_push_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags))); + } + } + if (r->nt_version & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) { + NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->next_closest_site)); + } + NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->domain_uuid)); + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +/* Manually modified to only pull some parts of the structure if certain flags provided */ +enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_RESPONSE_EX *r, + uint32_t nt_version_flags) +{ + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ZERO_STRUCTP(r); + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_netlogon_command(ndr, NDR_SCALARS, &r->command)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz)); + NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type)); + NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain_name)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site)); + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site)); + if (nt_version_flags & NETLOGON_NT_VERSION_5EX_WITH_IP) { + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sockaddr_size)); + { + struct ndr_pull *_ndr_sockaddr; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sockaddr, 0, r->sockaddr_size)); + NDR_CHECK(ndr_pull_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sockaddr, 0, r->sockaddr_size)); + } + } + if (nt_version_flags & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) { + NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->next_closest_site)); + } + NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version)); + if (r->nt_version != nt_version_flags) { + return NDR_ERR_VALIDATE; + } + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->domain_uuid)); + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_netlogon_samlogon_response(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct netlogon_samlogon_response *r) +{ + if (r->ntver == NETLOGON_NT_VERSION_1) { + NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40( + ndr, ndr_flags, &r->data.nt4)); + } else if (r->ntver & NETLOGON_NT_VERSION_5EX) { + NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags( + ndr, ndr_flags, &r->data.nt5_ex)); + } else if (r->ntver & NETLOGON_NT_VERSION_5) { + NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE( + ndr, ndr_flags, &r->data.nt5)); + } else { + return NDR_ERR_BAD_SWITCH; + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_netlogon_samlogon_response(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct netlogon_samlogon_response *r) +{ + if (ndr->data_size < 8) { + return NDR_ERR_BUFSIZE; + } + + /* lmnttoken */ + if (SVAL(ndr->data, ndr->data_size - 4) != 0xffff) { + return NDR_ERR_TOKEN; + } + /* lm20token */ + if (SVAL(ndr->data, ndr->data_size - 2) != 0xffff) { + return NDR_ERR_TOKEN; + } + + r->ntver = IVAL(ndr->data, ndr->data_size - 8); + + if (r->ntver == NETLOGON_NT_VERSION_1) { + NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40( + ndr, ndr_flags, &r->data.nt4)); + } else if (r->ntver & NETLOGON_NT_VERSION_5EX) { + NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags( + ndr, ndr_flags, &r->data.nt5_ex, r->ntver)); + if (ndr->offset < ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES, + "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]", + ndr->offset, ndr->data_size); + } + } else if (r->ntver & NETLOGON_NT_VERSION_5) { + NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE( + ndr, ndr_flags, &r->data.nt5)); + } else { + return NDR_ERR_BAD_SWITCH; + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_netlogon_samlogon_response(struct ndr_print *ndr, const char *name, const struct netlogon_samlogon_response *r) +{ + ndr_print_struct(ndr, name, "netlogon_samlogon_response"); + if (r == NULL) { ndr_print_null(ndr); return; } + if (r->ntver == NETLOGON_NT_VERSION_1) { + ndr_print_NETLOGON_SAM_LOGON_RESPONSE_NT40(ndr, "data.nt4", &r->data.nt4); + } else if (r->ntver & NETLOGON_NT_VERSION_5EX) { + ndr_print_NETLOGON_SAM_LOGON_RESPONSE_EX(ndr, "data.nt5_ex", &r->data.nt5_ex); + } else if (r->ntver & NETLOGON_NT_VERSION_5) { + ndr_print_NETLOGON_SAM_LOGON_RESPONSE(ndr, "data.nt5", &r->data.nt5); + } +} diff --git a/librpc/ndr/ndr_nbt.h b/librpc/ndr/ndr_nbt.h new file mode 100644 index 0000000..00ee8a1 --- /dev/null +++ b/librpc/ndr/ndr_nbt.h @@ -0,0 +1,42 @@ +#/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special netlogon types + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Andrew Bartlett 2008 + Copyright (C) Guenther Deschner 2011 + + 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 . +*/ + +/* The following definitions come from ../librpc/ndr/ndr_nbt.c */ + +#ifndef _LIBRPC_NDR_NDR_NBT_H +#define _LIBRPC_NDR_NDR_NBT_H + +#include "librpc/gen_ndr/nbt.h" + +NDR_SCALAR_PROTO(nbt_string, const char *) + +enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_REQUEST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_REQUEST *r); +enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_REQUEST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_REQUEST *r); +enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_RESPONSE_EX *r); +enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_RESPONSE_EX *r, + uint32_t nt_version_flags); +enum ndr_err_code ndr_push_netlogon_samlogon_response(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct netlogon_samlogon_response *r); +enum ndr_err_code ndr_pull_netlogon_samlogon_response(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct netlogon_samlogon_response *r); +void ndr_print_netlogon_samlogon_response(struct ndr_print *ndr, const char *name, const struct netlogon_samlogon_response *r); + +#endif /* _LIBRPC_NDR_NDR_NBT_H */ diff --git a/librpc/ndr/ndr_negoex.c b/librpc/ndr/ndr_negoex.c new file mode 100644 index 0000000..26b98f4 --- /dev/null +++ b/librpc/ndr/ndr_negoex.c @@ -0,0 +1,521 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special NEGOEX structures + + Copyright (C) Stefan Metzmacher 2015 + + 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 . +*/ +#include "includes.h" +#include "librpc/gen_ndr/ndr_negoex.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/ndr/ndr_negoex.h" + +void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r) +{ + ndr_print_struct(ndr, name, "negoex_BYTE_VECTOR"); + if (r == NULL) { ndr_print_null(ndr); return; } + ndr->depth++; + ndr_print_DATA_BLOB(ndr, "blob", r->blob); + ndr->depth--; +} + +enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_BYTE_VECTOR *r) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->blob.data)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->blob.length)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->blob.data) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->blob.data)); +#if 0 + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->blob.length)); +#endif + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->blob.data, r->blob.length)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->blob.data)); + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_BYTE_VECTOR *r) +{ + uint32_t _ptr_data; + uint32_t size_data_1 = 0; + TALLOC_CTX *_mem_save_data_0 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + r->_dummy = NULL; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data)); + if (_ptr_data) { + NDR_PULL_ALLOC(ndr, r->blob.data); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->blob.data, _ptr_data)); + } else { + r->blob.data = NULL; + } + r->blob.length = 0; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size_data_1)); + r->_length = size_data_1; + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->blob.data) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->blob.data)); + _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->blob.data, 0); +#if 0 + NDR_CHECK(ndr_pull_array_size(ndr, &r->blob.data)); + size_data_1 = ndr_get_array_size(ndr, &r->blob.data); +#else + size_data_1 = r->_length; +#endif + NDR_PULL_ALLOC_N(ndr, r->blob.data, size_data_1); + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->blob.data, size_data_1)); + r->blob.length = size_data_1; + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } +#if 0 + if (r->blob.data) { + NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->blob.data, r->blob.length)); + } +#endif + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r) +{ + uint32_t cntr_array_1; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array)); +#if 0 + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count)); +#endif + for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) { + NDR_CHECK(ndr_push_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array)); + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r) +{ + uint32_t _ptr_array; + uint32_t size_array_1 = 0; + uint32_t cntr_array_1; + TALLOC_CTX *_mem_save_array_0 = NULL; + TALLOC_CTX *_mem_save_array_1 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array)); + if (_ptr_array) { + NDR_PULL_ALLOC(ndr, r->array); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array)); + } else { + r->array = NULL; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array)); + _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); +#if 0 + NDR_CHECK(ndr_pull_array_size(ndr, &r->array)); + size_array_1 = ndr_get_array_size(ndr, &r->array); +#else + size_array_1 = r->count; +#endif + NDR_PULL_ALLOC_N(ndr, r->array, size_array_1); + _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); + for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) { + NDR_CHECK(ndr_pull_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } +#if 0 + if (r->array) { + NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count)); + } +#endif + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_EXTENSION_VECTOR *r) +{ + uint32_t cntr_array_1; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array)); +#if 0 + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count)); +#endif + for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) { + NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) { + NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1])); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array)); + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_EXTENSION_VECTOR *r) +{ + uint32_t _ptr_array; + uint32_t size_array_1 = 0; + uint32_t cntr_array_1; + TALLOC_CTX *_mem_save_array_0 = NULL; + TALLOC_CTX *_mem_save_array_1 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array)); + if (_ptr_array) { + NDR_PULL_ALLOC(ndr, r->array); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array)); + } else { + r->array = NULL; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array)); + _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); +#if 0 + NDR_CHECK(ndr_pull_array_size(ndr, &r->array)); + size_array_1 = ndr_get_array_size(ndr, &r->array); +#else + size_array_1 = r->count; +#endif + NDR_PULL_ALLOC_N(ndr, r->array, size_array_1); + _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); + for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) { + NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) { + NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } +#if 0 + if (r->array) { + NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count)); + } +#endif + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_ALERT_VECTOR *r) +{ + uint32_t cntr_array_1; + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array)); +#if 0 + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count)); +#endif + for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) { + NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) { + NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1])); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array)); + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_ALERT_VECTOR *r) +{ + uint32_t _ptr_array; + uint32_t size_array_1 = 0; + uint32_t cntr_array_1; + TALLOC_CTX *_mem_save_array_0 = NULL; + TALLOC_CTX *_mem_save_array_1 = NULL; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array)); + if (_ptr_array) { + NDR_PULL_ALLOC(ndr, r->array); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array)); + } else { + r->array = NULL; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->array) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array)); + _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); +#if 0 + NDR_CHECK(ndr_pull_array_size(ndr, &r->array)); + size_array_1 = ndr_get_array_size(ndr, &r->array); +#else + size_array_1 = r->count; +#endif + NDR_PULL_ALLOC_N(ndr, r->array, size_array_1); + _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->array, 0); + for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) { + NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) { + NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } +#if 0 + if (r->array) { + NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count)); + } +#endif + } + return NDR_ERR_SUCCESS; +} + +size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r) +{ + size_t size = 0; + + size += 8; /* signature */ + size += 4; /* type */ + size += 4; /* sequence_number */ + size += 4; /* header_length */ + size += 4; /* message_length */ + size += 16; /* conversation_id */ + + switch (r->type) { + case NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO: + case NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO: + size += 32; /* random */ + size += 8; /* protocol_version */ + size += 8; /* auth_schemes */ + size += 8; /* extensions */ + break; + + case NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA: + case NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA: + case NEGOEX_MESSAGE_TYPE_CHALLENGE: + case NEGOEX_MESSAGE_TYPE_AP_REQUEST: + size += 16; /* auth_scheme */ + size += 8; /* exchange */ + break; + + case NEGOEX_MESSAGE_TYPE_VERIFY: + size += 16; /* auth_scheme */ + size += 4; /* checksum.header_length */ + size += 4; /* checksum.scheme */ + size += 4; /* checksum.type */ + size += 8; /* checksum.value */ + break; + + case NEGOEX_MESSAGE_TYPE_ALERT: + size += 16; /* auth_scheme */ + size += 4; /* status */ + size += 8; /* alerts */ + break; + } + + return size; +} + +enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE *r) +{ + uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr); + uint32_t size_signature_0 = 0; + uint32_t start_data_size = ndr->data_size; + uint32_t saved_offset = 0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset)); + size_signature_0 = 8; + NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->signature, size_signature_0, sizeof(uint8_t), CH_DOS)); + NDR_CHECK(ndr_pull_negoex_MESSAGE_TYPE(ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sequence_number)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->header_length)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->message_length)); + saved_offset = ndr->offset; + ndr->offset = ndr->relative_base_offset; + NDR_PULL_NEED_BYTES(ndr, r->message_length); + ndr->data_size = ndr->offset + r->message_length; + ndr->offset = saved_offset; + NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->conversation_id)); + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->p, r->type)); + NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_SCALARS, &r->p)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + ndr->offset = ndr->data_size; + ndr->data_size = start_data_size; + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r)); + saved_offset = ndr->offset; + ndr->offset = ndr->relative_base_offset; + NDR_PULL_NEED_BYTES(ndr, r->message_length); + ndr->data_size = ndr->offset + r->message_length; + ndr->offset = saved_offset; + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->p, r->type)); + NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_BUFFERS, &r->p)); + ndr->offset = ndr->data_size; + ndr->data_size = start_data_size; + } + ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_MESSAGE_ARRAY *r) +{ + uint32_t cntr_messages_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + for (cntr_messages_0 = 0; cntr_messages_0 < (r->count); cntr_messages_0++) { + NDR_CHECK(ndr_push_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0])); + } + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE_ARRAY *r) +{ + uint32_t size_messages_0 = 0; + uint32_t cntr_messages_0; + TALLOC_CTX *_mem_save_messages_0 = NULL; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + uint32_t saved_offset = ndr->offset; + uint32_t available = 0; + NDR_CHECK(ndr_pull_align(ndr, 5)); + r->count = 0; + available = ndr->data_size - ndr->offset; + while (available > 0) { + uint32_t length; + + /* + * The common header is 40 bytes + * and message_length is at offset 20 + */ + NDR_PULL_NEED_BYTES(ndr, 40); + ndr->offset += 20; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length)); + ndr->offset -= 24; + if (length < 40) { + /* + * let the pull function catch the error + */ + length = 40; + } + NDR_PULL_NEED_BYTES(ndr, length); + ndr->offset += length; + available -= length; + r->count++; + } + ndr->offset = saved_offset; + size_messages_0 = r->count; + NDR_PULL_ALLOC_N(ndr, r->messages, size_messages_0); + _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0); + for (cntr_messages_0 = 0; cntr_messages_0 < (size_messages_0); cntr_messages_0++) { + NDR_CHECK(ndr_pull_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0); + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_negoex.h b/librpc/ndr/ndr_negoex.h new file mode 100644 index 0000000..094275c --- /dev/null +++ b/librpc/ndr/ndr_negoex.h @@ -0,0 +1,37 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special NEGOEX structures + + Copyright (C) Stefan Metzmacher 2015 + + 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 . +*/ + +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/negoex.h" + +_PUBLIC_ void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_BYTE_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_BYTE_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_EXTENSION_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_EXTENSION_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_ALERT_VECTOR *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_ALERT_VECTOR *r); +_PUBLIC_ size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE *r); +_PUBLIC_ enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_MESSAGE_ARRAY *r); +_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE_ARRAY *r); diff --git a/librpc/ndr/ndr_netlogon.c b/librpc/ndr/ndr_netlogon.c new file mode 100644 index 0000000..56f0eab --- /dev/null +++ b/librpc/ndr/ndr_netlogon.c @@ -0,0 +1,65 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special netlogon types + + Copyright (C) Guenther Deschner 2008 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_samr.h" + +_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit r) +{ + if (r > 0xff) return NDR_ERR_BUFSIZE; + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r)); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit *r) +{ + uint8_t v; + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_netr_SamDatabaseID8Bit(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID8Bit r) +{ + ndr_print_netr_SamDatabaseID(ndr, name, r); +} + +_PUBLIC_ enum ndr_err_code ndr_push_netr_DeltaEnum8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit r) +{ + if (r > 0xff) return NDR_ERR_BUFSIZE; + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r)); + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_netr_DeltaEnum8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit *r) +{ + uint8_t v; + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_netr_DeltaEnum8Bit(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum8Bit r) +{ + ndr_print_netr_DeltaEnum(ndr, name, r); +} diff --git a/librpc/ndr/ndr_netlogon.h b/librpc/ndr/ndr_netlogon.h new file mode 100644 index 0000000..66fadde --- /dev/null +++ b/librpc/ndr/ndr_netlogon.h @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special netlogon types + + Copyright (C) Guenther Deschner 2008 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit r); +_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit *r); +_PUBLIC_ void ndr_print_netr_SamDatabaseID8Bit(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID8Bit r); + +_PUBLIC_ enum ndr_err_code ndr_push_netr_DeltaEnum8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit r); +_PUBLIC_ enum ndr_err_code ndr_pull_netr_DeltaEnum8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit *r); +_PUBLIC_ void ndr_print_netr_DeltaEnum8Bit(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum8Bit r); diff --git a/librpc/ndr/ndr_ntlmssp.c b/librpc/ndr/ndr_ntlmssp.c new file mode 100644 index 0000000..723ae9c --- /dev/null +++ b/librpc/ndr/ndr_ntlmssp.c @@ -0,0 +1,195 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ntlmssp structures + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_ntlmssp.h" + +_PUBLIC_ size_t ndr_ntlmssp_string_length(uint32_t negotiate_flags, const char *s) +{ + if (!s) { + return 0; + } + + if (negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE) { + return strlen(s) * 2; + } + + return strlen(s); +} + +_PUBLIC_ libndr_flags ndr_ntlmssp_negotiated_string_flags(uint32_t negotiate_flags) +{ + libndr_flags flags = LIBNDR_FLAG_STR_NOTERM | + LIBNDR_FLAG_STR_CHARLEN | + LIBNDR_FLAG_REMAINING; + + if (!(negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE)) { + flags |= LIBNDR_FLAG_STR_ASCII; + } + + return flags; +} + +_PUBLIC_ enum ndr_err_code ndr_push_AV_PAIR_LIST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AV_PAIR_LIST *r) +{ + uint32_t cntr_pair_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) { + NDR_CHECK(ndr_push_AV_PAIR(ndr, NDR_SCALARS, &r->pair[cntr_pair_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) { + NDR_CHECK(ndr_push_AV_PAIR(ndr, NDR_BUFFERS, &r->pair[cntr_pair_0])); + } + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_AV_PAIR_LIST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AV_PAIR_LIST *r) +{ + uint32_t cntr_pair_0; + TALLOC_CTX *_mem_save_pair_0; + if (ndr_flags & NDR_SCALARS) { + uint32_t offset = 0; + NDR_CHECK(ndr_pull_align(ndr, 4)); + r->count = 0; + if (ndr->data_size > 0) { + NDR_PULL_NEED_BYTES(ndr, 4); + } + while (offset + 4 <= ndr->data_size) { + uint16_t length; + uint16_t type; + type = SVAL(ndr->data + offset, 0); + if (type == MsvAvEOL) { + r->count++; + break; + } + length = SVAL(ndr->data + offset, 2); + offset += length + 4; + r->count++; + } + NDR_PULL_ALLOC_N(ndr, r->pair, r->count); + _mem_save_pair_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->pair, 0); + for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) { + NDR_CHECK(ndr_pull_AV_PAIR(ndr, NDR_SCALARS, &r->pair[cntr_pair_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pair_0, 0); + } + if (ndr_flags & NDR_BUFFERS) { + _mem_save_pair_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->pair, 0); + for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) { + NDR_CHECK(ndr_pull_AV_PAIR(ndr, NDR_BUFFERS, &r->pair[cntr_pair_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pair_0, 0); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_ntlmssp_nt_response(TALLOC_CTX *mem_ctx, + const DATA_BLOB *nt_response, + bool ntlmv2) +{ + enum ndr_err_code ndr_err; + + if (ntlmv2) { + struct NTLMv2_RESPONSE nt; + if (nt_response->length > 24) { + ndr_err = ndr_pull_struct_blob(nt_response, mem_ctx, &nt, + (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &nt); + } + } + } else { + struct NTLM_RESPONSE nt; + if (nt_response->length == 24) { + ndr_err = ndr_pull_struct_blob(nt_response, mem_ctx, &nt, + (ndr_pull_flags_fn_t)ndr_pull_NTLM_RESPONSE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(NTLM_RESPONSE, &nt); + } + } + } +} + +_PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx, + const DATA_BLOB *lm_response, + bool ntlmv2) +{ + enum ndr_err_code ndr_err; + + if (ntlmv2) { + struct LMv2_RESPONSE lm; + if (lm_response->length == 24) { + ndr_err = ndr_pull_struct_blob(lm_response, mem_ctx, &lm, + (ndr_pull_flags_fn_t)ndr_pull_LMv2_RESPONSE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(LMv2_RESPONSE, &lm); + } + } + } else { + struct LM_RESPONSE lm; + if (lm_response->length == 24) { + ndr_err = ndr_pull_struct_blob(lm_response, mem_ctx, &lm, + (ndr_pull_flags_fn_t)ndr_pull_LM_RESPONSE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(LM_RESPONSE, &lm); + } + } + } +} + +_PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r) +{ + int level; + level = ndr_print_steal_switch_value(ndr, r); + switch (level) { + case NTLMSSP_NEGOTIATE_VERSION: + ndr_print_ntlmssp_VERSION(ndr, name, &r->version); + break; + + default: + break; + + } +} + +_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list, + enum ntlmssp_AvId AvId) +{ + struct AV_PAIR *res = NULL; + uint32_t i = 0; + + for (i = 0; i < av_list->count; i++) { + if (av_list->pair[i].AvId != AvId) { + continue; + } + + res = discard_const_p(struct AV_PAIR, &av_list->pair[i]); + break; + } + + return res; +} diff --git a/librpc/ndr/ndr_ntlmssp.h b/librpc/ndr/ndr_ntlmssp.h new file mode 100644 index 0000000..2326a08 --- /dev/null +++ b/librpc/ndr/ndr_ntlmssp.h @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ntlmssp structures + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +_PUBLIC_ size_t ndr_ntlmssp_string_length(uint32_t negotiate_flags, const char *s); +_PUBLIC_ libndr_flags ndr_ntlmssp_negotiated_string_flags(uint32_t negotiate_flags); +_PUBLIC_ enum ndr_err_code ndr_push_AV_PAIR_LIST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AV_PAIR_LIST *r); +_PUBLIC_ enum ndr_err_code ndr_pull_AV_PAIR_LIST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AV_PAIR_LIST *r); +_PUBLIC_ void ndr_print_ntlmssp_nt_response(TALLOC_CTX *mem_ctx, + const DATA_BLOB *nt_response, + bool ntlmv2); +_PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx, + const DATA_BLOB *lm_response, + bool ntlmv2); +_PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r); + +_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list, + enum ntlmssp_AvId AvId); diff --git a/librpc/ndr/ndr_ntprinting.c b/librpc/ndr/ndr_ntprinting.c new file mode 100644 index 0000000..22010ff --- /dev/null +++ b/librpc/ndr/ndr_ntprinting.c @@ -0,0 +1,87 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ntprinting structures + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_ntprinting.h" + +_PUBLIC_ libndr_flags ndr_ntprinting_string_flags(libndr_flags string_flags) +{ + libndr_flags flags = LIBNDR_FLAG_STR_NULLTERM; + + if (string_flags & LIBNDR_FLAG_STR_ASCII) { + flags |= LIBNDR_FLAG_STR_ASCII; + } else if (string_flags & LIBNDR_FLAG_STR_RAW8) { + flags |= LIBNDR_FLAG_STR_RAW8; + } else { + flags |= LIBNDR_FLAG_STR_UTF8; + } + + return flags; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_ntprinting_printer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ntprinting_printer *r) +{ + uint32_t _ptr_devmode; + TALLOC_CTX *_mem_save_devmode_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_ntprinting_printer_info(ndr, NDR_SCALARS, &r->info)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_devmode)); + if (_ptr_devmode) { + NDR_PULL_ALLOC(ndr, r->devmode); + } else { + r->devmode = NULL; + } + } + if (ndr_flags & NDR_BUFFERS) { + if (r->devmode) { + _mem_save_devmode_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->devmode, 0); + r->devmode->string_flags = r->info.string_flags; + NDR_CHECK(ndr_pull_ntprinting_devicemode(ndr, NDR_SCALARS|NDR_BUFFERS, r->devmode)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_devmode_0, 0); + } + } + if (ndr_flags & NDR_SCALARS) { + r->count = 0; + NDR_PULL_ALLOC_N(ndr, r->printer_data, r->count); + while (ndr->offset + 4 <= ndr->data_size) { + uint32_t ptr = 0; + ptr = IVAL(ndr->data, ndr->offset); + if (ptr == 0) { + ndr->offset = ndr->offset + 4; + break; + } + r->printer_data = talloc_realloc(ndr, r->printer_data, struct ntprinting_printer_data, r->count + 1); + NDR_ERR_HAVE_NO_MEMORY(r->printer_data); + r->printer_data[r->count].string_flags = r->info.string_flags; + NDR_CHECK(ndr_pull_ntprinting_printer_data(ndr, NDR_SCALARS, &r->printer_data[r->count])); + r->count++; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_ntprinting.h b/librpc/ndr/ndr_ntprinting.h new file mode 100644 index 0000000..4b89707 --- /dev/null +++ b/librpc/ndr/ndr_ntprinting.h @@ -0,0 +1,27 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special ntprinting structures + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_ntprinting.h" + +_PUBLIC_ libndr_flags ndr_ntprinting_string_flags(libndr_flags string_flags); + +_PUBLIC_ enum ndr_err_code ndr_pull_ntprinting_printer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ntprinting_printer *r); diff --git a/librpc/ndr/ndr_orpc.c b/librpc/ndr/ndr_orpc.c new file mode 100644 index 0000000..80d9870 --- /dev/null +++ b/librpc/ndr/ndr_orpc.c @@ -0,0 +1,163 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling DCOM string arrays + + Copyright (C) Jelmer Vernooij 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 . +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_orpc.h" + +enum ndr_err_code ndr_pull_DUALSTRINGARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct DUALSTRINGARRAY *ar) +{ + uint16_t num_entries, security_offset; + uint16_t towerid; + uint32_t towernum = 0, conformant_size; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &conformant_size)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &num_entries)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &security_offset)); + + ar->stringbindings = talloc_array(ndr, struct STRINGBINDING *, 1); + ar->stringbindings[0] = NULL; + + do { + /* 'Peek' */ + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid)); + + if (towerid > 0) { + ndr->offset -= 2; + ar->stringbindings = talloc_realloc(ndr, ar->stringbindings, struct STRINGBINDING *, towernum+2); + ar->stringbindings[towernum] = talloc(ndr, struct STRINGBINDING); + NDR_CHECK(ndr_pull_STRINGBINDING(ndr, ndr_flags, ar->stringbindings[towernum])); + towernum++; + } + } while (towerid != 0); + + ar->stringbindings[towernum] = NULL; + towernum = 0; + + ar->securitybindings = talloc_array(ndr, struct SECURITYBINDING *, 1); + ar->securitybindings[0] = NULL; + + do { + /* 'Peek' */ + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid)); + + if (towerid > 0) { + ndr->offset -= 2; + ar->securitybindings = talloc_realloc(ndr, ar->securitybindings, struct SECURITYBINDING *, towernum+2); + ar->securitybindings[towernum] = talloc(ndr, struct SECURITYBINDING); + NDR_CHECK(ndr_pull_SECURITYBINDING(ndr, ndr_flags, ar->securitybindings[towernum])); + towernum++; + } + } while (towerid != 0); + + ar->securitybindings[towernum] = NULL; + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_DUALSTRINGARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct DUALSTRINGARRAY *ar) +{ + return ndr_push_error(ndr, NDR_ERR_STRING, "ndr_push_DUALSTRINGARRAY not implemented"); +} + +/* + print a dom_sid +*/ +void ndr_print_DUALSTRINGARRAY(struct ndr_print *ndr, const char *name, const struct DUALSTRINGARRAY *ar) +{ + int i; + ndr->print(ndr, "%-25s: DUALSTRINGARRAY", name); + ndr->depth++; + ndr->print(ndr, "STRING BINDINGS"); + ndr->depth++; + for (i=0;ar->stringbindings[i];i++) { + char idx[13]; /* 2^32 has 10 digits */ + snprintf(idx, sizeof(idx), "[%d]", i); + ndr_print_STRINGBINDING(ndr, idx, ar->stringbindings[i]); + } + ndr->depth--; + ndr->print(ndr, "SECURITY BINDINGS"); + ndr->depth++; + for (i=0;ar->securitybindings[i];i++) { + char idx[13]; /* 2^32 has 10 digits */ + snprintf(idx, sizeof(idx), "[%d]", i); + ndr_print_SECURITYBINDING(ndr, idx, ar->securitybindings[i]); + } + ndr->depth--; +} + +enum ndr_err_code ndr_pull_STRINGARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct STRINGARRAY *ar) +{ + uint16_t towerid; + uint32_t towernum = 0; + uint16_t num_entries; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &num_entries)); + + ar->stringbindings = talloc_array(ndr, struct STRINGBINDING *, 1); + ar->stringbindings[0] = NULL; + + do { + /* 'Peek' */ + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid)); + + if (towerid > 0) { + ndr->offset -= 2; + ar->stringbindings = talloc_realloc(ndr, ar->stringbindings, struct STRINGBINDING *, towernum+2); + ar->stringbindings[towernum] = talloc(ndr, struct STRINGBINDING); + NDR_CHECK(ndr_pull_STRINGBINDING(ndr, ndr_flags, ar->stringbindings[towernum])); + towernum++; + } + } while (towerid != 0); + + ar->stringbindings[towernum] = NULL; + + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_STRINGARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct STRINGARRAY *ar) +{ + return ndr_push_error(ndr, NDR_ERR_STRING, "ndr_push_STRINGARRAY not implemented"); +} + +/* + print a dom_sid +*/ +void ndr_print_STRINGARRAY(struct ndr_print *ndr, const char *name, const struct STRINGARRAY *ar) +{ + int i; + ndr->print(ndr, "%-25s: STRINGARRAY", name); + ndr->depth++; + for (i=0;ar->stringbindings[i];i++) { + char idx[13]; /* 2^32 has 10 digits */ + snprintf(idx, sizeof(idx), "[%d]", i); + ndr_print_STRINGBINDING(ndr, idx, ar->stringbindings[i]); + } + ndr->depth--; +} diff --git a/librpc/ndr/ndr_preg.c b/librpc/ndr/ndr_preg.c new file mode 100644 index 0000000..8074e1e --- /dev/null +++ b/librpc/ndr/ndr_preg.c @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling preg structures + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_preg.h" + +_PUBLIC_ enum ndr_err_code ndr_push_preg_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct preg_file *r) +{ + uint32_t cntr_entries_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_preg_header(ndr, NDR_SCALARS, &r->header)); + for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) { + NDR_CHECK(ndr_push_preg_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0])); + } + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_preg_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct preg_file *r) +{ + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_preg_header(ndr, NDR_SCALARS, &r->header)); + r->num_entries = 0; + NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries); + while (ndr->offset + 12 <= ndr->data_size) { + r->entries = talloc_realloc(ndr, r->entries, struct preg_entry, r->num_entries + 1); + NDR_ERR_HAVE_NO_MEMORY(r->entries); + NDR_CHECK(ndr_pull_preg_entry(ndr, NDR_SCALARS, &r->entries[r->num_entries])); + r->num_entries++; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_preg.h b/librpc/ndr/ndr_preg.h new file mode 100644 index 0000000..f634225 --- /dev/null +++ b/librpc/ndr/ndr_preg.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling preg structures + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_push_preg_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct preg_file *r); +_PUBLIC_ enum ndr_err_code ndr_pull_preg_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct preg_file *r); diff --git a/librpc/ndr/ndr_private.h b/librpc/ndr/ndr_private.h new file mode 100644 index 0000000..08521be --- /dev/null +++ b/librpc/ndr/ndr_private.h @@ -0,0 +1,32 @@ +/* + 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 . +*/ + +/* This is not a public header file that is installed as part of Samba. + * + * Instead, this is to allow our python layer to get to the + * NDR_TOKEN_MAX_LIST_SIZE +*/ + +#ifndef __NDR_PRIVATE_H__ +#define __NDR_PRIVATE_H__ + +size_t ndr_token_max_list_size(void); + +#endif diff --git a/librpc/ndr/ndr_rap.c b/librpc/ndr/ndr_rap.c new file mode 100644 index 0000000..ea18a08 --- /dev/null +++ b/librpc/ndr/ndr_rap.c @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special rap types + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_rap.h" + +_PUBLIC_ void ndr_print_rap_status(struct ndr_print *ndr, const char *name, enum rap_status r) +{ + ndr_print_WERROR(ndr, name, W_ERROR(r)); +} diff --git a/librpc/ndr/ndr_rap.h b/librpc/ndr/ndr_rap.h new file mode 100644 index 0000000..35a03b1 --- /dev/null +++ b/librpc/ndr/ndr_rap.h @@ -0,0 +1,22 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special rap types + + Copyright (C) Guenther Deschner 2010 + + 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 . +*/ + +_PUBLIC_ void ndr_print_rap_status(struct ndr_print *ndr, const char *name, enum rap_status r); diff --git a/librpc/ndr/ndr_schannel.c b/librpc/ndr/ndr_schannel.c new file mode 100644 index 0000000..6b08a79 --- /dev/null +++ b/librpc/ndr/ndr_schannel.c @@ -0,0 +1,107 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special schannel structures + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_schannel.h" +#include "../librpc/ndr/ndr_schannel.h" +#include "../libcli/nbt/libnbt.h" + +_PUBLIC_ void ndr_print_NL_AUTH_MESSAGE_BUFFER(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER *r) +{ + int level; + level = ndr_print_steal_switch_value(ndr, r); + switch (level) { + case NL_FLAG_OEM_NETBIOS_DOMAIN_NAME: + ndr_print_string(ndr, name, r->a); + break; + + case NL_FLAG_OEM_NETBIOS_COMPUTER_NAME: + ndr_print_string(ndr, name, r->a); + break; + + case NL_FLAG_UTF8_DNS_DOMAIN_NAME: + ndr_print_nbt_string(ndr, name, r->u); + break; + + case NL_FLAG_UTF8_DNS_HOST_NAME: + ndr_print_nbt_string(ndr, name, r->u); + break; + + case NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME: + ndr_print_nbt_string(ndr, name, r->u); + break; + + default: + break; + + } +} + +_PUBLIC_ void ndr_print_NL_AUTH_MESSAGE_BUFFER_REPLY(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER_REPLY *r) +{ + int level; + level = ndr_print_steal_switch_value(ndr, r); + switch (level) { + case NL_NEGOTIATE_RESPONSE: + ndr_print_uint32(ndr, name, r->dummy); + break; + + default: + break; + + } +} + +void dump_NL_AUTH_SIGNATURE(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob) +{ + enum ndr_err_code ndr_err; + uint16_t signature_algorithm; + + if (blob->length < 2) { + return; + } + + signature_algorithm = SVAL(blob->data, 0); + + switch (signature_algorithm) { + case NL_SIGN_HMAC_MD5: { + struct NL_AUTH_SIGNATURE r; + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &r); + } + break; + } + case NL_SIGN_HMAC_SHA256: { + struct NL_AUTH_SHA2_SIGNATURE r; + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SHA2_SIGNATURE); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(NL_AUTH_SHA2_SIGNATURE, &r); + } + break; + } + default: + break; + } +} diff --git a/librpc/ndr/ndr_schannel.h b/librpc/ndr/ndr_schannel.h new file mode 100644 index 0000000..d57278c --- /dev/null +++ b/librpc/ndr/ndr_schannel.h @@ -0,0 +1,25 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special schannel structures + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +void ndr_print_NL_AUTH_MESSAGE_BUFFER(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER *r); +void ndr_print_NL_AUTH_MESSAGE_BUFFER_REPLY(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER_REPLY *r); +void dump_NL_AUTH_SIGNATURE(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob); diff --git a/librpc/ndr/ndr_sec_helper.c b/librpc/ndr/ndr_sec_helper.c new file mode 100644 index 0000000..1a156b0 --- /dev/null +++ b/librpc/ndr/ndr_sec_helper.c @@ -0,0 +1,457 @@ +/* + Unix SMB/CIFS implementation. + + fast routines for getting the wire size of security objects + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Stefan Metzmacher 2006-2008 + + 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 . +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "../libcli/security/security.h" + + +/* + * Find the wire size of a security_ace that has no trailing coda. + * This is used in ndr_pull_security_ace() generated from security.idl + * to work out where the coda starts (and in ndr_size_security_ace() + * just below). + */ +static size_t ndr_size_security_ace_core(const struct security_ace *ace, libndr_flags flags) +{ + size_t ret; + + if (!ace) return 0; + + ret = 8 + ndr_size_dom_sid(&ace->trustee, flags); + if (sec_ace_object(ace->type)) { + ret += 4; /* uint32 bitmap ace->object.object.flags */ + if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) { + ret += 16; /* GUID ace->object.object.type.type */ + } + if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) { + ret += 16; /* GUID ace->object.object.inherited_type.inherited_type */ + } + } + + return ret; +} + +/* + return the wire size of a security_ace +*/ +size_t ndr_size_security_ace(const struct security_ace *ace, libndr_flags flags) +{ + size_t base = ndr_size_security_ace_core(ace, flags); + size_t ret = base; + if (sec_ace_callback(ace->type)) { + ret += ace->coda.conditions.length; + } else if (ace->type == SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) { + ret += ndr_size_security_ace_coda(&ace->coda, ace->type, flags); + } else { + /* + * Normal ACEs have a coda.ignored blob that is always or + * almost always empty. We aren't going to push it (it is + * ignored), so we don't add that length to the size. + */ + } + /* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */ + ret = (ret + 3ULL) & ~3ULL; + if (unlikely(ret < base)) { + /* overflow, and there's not much we can do anyway */ + return 0; + } + return ret; +} + + +static inline enum ndr_err_code ndr_maybe_pull_security_ace_object_ctr(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct security_ace *r) +{ + /* + * If this is not an object ACE (as is usually common), + * ndr_pull_security_ace_object_ctr() will do nothing. + * + * By avoiding calling the function in that case, we avoid some + * tallocing and ndr token busywork. + */ + bool is_object = sec_ace_object(r->type); + if (is_object) { + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, is_object)); + NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, ndr_flags, &r->object)); + } + return NDR_ERR_SUCCESS; +} + + +_PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_ace *r) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask)); + NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_SCALARS, r)); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee)); + if (!sec_ace_has_extra_blob(r->type)) { + r->coda.ignored.data = NULL; + r->coda.ignored.length = 0; + } else { + struct ndr_pull *_ndr_coda; + ssize_t sub_size = ndr_subcontext_size_of_ace_coda(r, r->size, ndr->flags); + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_coda, 0, sub_size)); + NDR_CHECK(ndr_pull_set_switch_value(_ndr_coda, &r->coda, r->type)); + NDR_CHECK(ndr_pull_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda)); + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_coda, 0, sub_size)); + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, r)); + } + return NDR_ERR_SUCCESS; +} + + +static inline enum ndr_err_code ndr_maybe_push_security_ace_object_ctr(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct security_ace *r) +{ + /* + * ndr_push_security_ace_object_ctr() does nothing (except tallocing + * and ndr_token fiddling) unless the ACE is an object ACE, which is + * usually very unlikely. + */ + bool is_object = sec_ace_object(r->type); + if (is_object) { + NDR_CHECK(ndr_push_set_switch_value(ndr, &r->object, is_object)); + NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, ndr_flags, &r->object)); + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_ace *r) +{ + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_security_ace_type(ndr, NDR_SCALARS, r->type)); + NDR_CHECK(ndr_push_security_ace_flags(ndr, NDR_SCALARS, r->flags)); + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_ace(r, ndr->flags))); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->access_mask)); + NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_SCALARS, r)); + NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->trustee)); + if (sec_ace_has_extra_blob(r->type)) { + struct ndr_push *_ndr_coda; + size_t coda_size = ndr_subcontext_size_of_ace_coda( + r, + ndr_size_security_ace(r, ndr->flags), + ndr->flags); + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_coda, 0, coda_size)); + NDR_CHECK(ndr_push_set_switch_value(_ndr_coda, &r->coda, r->type)); + NDR_CHECK(ndr_push_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_coda, 0, coda_size)); + } + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_BUFFERS, r)); + } + return NDR_ERR_SUCCESS; +} + + +/* + * An ACE coda can't be bigger than the space allowed for by + * ace->size, so we need to check this from the context of the ACE. + * + * Usually the coda also can't be any smaller than the remaining + * space, because it is defined as a blob consuming everything it can. + * + * This is only used to find the size for the coda subcontext in + * security.idl. + */ +size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace, + size_t ace_size, + libndr_flags flags) +{ + size_t core_size; + if (ace_size == 0) { + return 0; + } + core_size = ndr_size_security_ace_core(ace, flags); + if (ace_size < core_size) { + return 0; + } + return ace_size - core_size; +} + +/* + return the wire size of a security_acl +*/ +size_t ndr_size_security_acl(const struct security_acl *theacl, libndr_flags flags) +{ + size_t ret; + int i; + if (!theacl) return 0; + ret = 8; + for (i=0;inum_aces;i++) { + ret += ndr_size_security_ace(&theacl->aces[i], flags); + } + return ret; +} + +/* + return the wire size of a security descriptor +*/ +size_t ndr_size_security_descriptor(const struct security_descriptor *sd, libndr_flags 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; +} + +/* + return the wire size of a dom_sid +*/ +size_t ndr_size_dom_sid(const struct dom_sid *sid, libndr_flags flags) +{ + if (!sid) return 0; + return 8 + 4*sid->num_auths; +} + +size_t ndr_size_dom_sid28(const struct dom_sid *sid, libndr_flags flags) +{ + if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) { + return 0; + } + return ndr_size_dom_sid(sid, flags); +} + +size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags) +{ + return ndr_size_dom_sid28(sid, flags); +} + +/* + print a dom_sid +*/ +void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + struct dom_sid_buf buf; + ndr->print(ndr, "%-25s: %s", name, dom_sid_str_buf(sid, &buf)); +} + +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); +} + + +/* + 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, ndr_flags_type ndr_flags, struct dom_sid *sid) +{ + uint32_t num_auths; + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths)); + NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid)); + if (sid->num_auths != num_auths) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad num_auths %"PRIu32"; should equal %"PRId8, + 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, ndr_flags_type ndr_flags, const struct dom_sid *sid) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_uint3264(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 up to 5 sub_auth +*/ +enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type 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; + + status = ndr_pull_advance(ndr, 28); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + talloc_free(subndr); + return status; + } + + status = ndr_pull_dom_sid(subndr, ndr_flags, sid); + if (!NDR_ERR_CODE_IS_SUCCESS(status)) { + /* handle a w2k bug which send random data in the buffer */ + ZERO_STRUCTP(sid); + } else if (sid->num_auths == 0) { + ZERO_STRUCT(sid->sub_auths); + } + + talloc_free(subndr); + 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, ndr_flags_type 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 up to 5 sub auths [%"PRId8"]", + 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, ndr_flags_type 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, ndr_flags_type ndr_flags, const struct dom_sid *sid) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (!sid) { + return NDR_ERR_SUCCESS; + } + + if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) { + return NDR_ERR_SUCCESS; + } + + return ndr_push_dom_sid(ndr, ndr_flags, sid); +} + +_PUBLIC_ enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, ndr_flags_type 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)); + if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) { + return ndr_push_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths)); + } + 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])); + } + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, ndr_flags_type 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_int8(ndr, NDR_SCALARS, &r->num_auths)); + if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths)); + } + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + ZERO_STRUCT(r->sub_auths); + 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])); + } + } + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_spoolss_buf.c b/librpc/ndr/ndr_spoolss_buf.c new file mode 100644 index 0000000..abeb884 --- /dev/null +++ b/librpc/ndr/ndr_spoolss_buf.c @@ -0,0 +1,1615 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling spoolss subcontext buffer structures + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Tim Potter 2003 + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + + +#include "includes.h" +#include "librpc/gen_ndr/ndr_spoolss.h" +#include "librpc/gen_ndr/ndr_security.h" + +#define NDR_SPOOLSS_PUSH_ENUM_IN(fn) do { \ + if (!r->in.buffer && r->in.offered != 0) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] but there's no buffer",\ + (unsigned)r->in.offered);\ + } else if (r->in.buffer && r->in.buffer->length != r->in.offered) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of r->in.buffer[%u]",\ + (unsigned)r->in.offered, (unsigned)r->in.buffer->length);\ + }\ + _r.in.buffer = r->in.buffer;\ + _r.in.offered = r->in.offered;\ + NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\ +} while(0) + +#define NDR_SPOOLSS_PUSH_ENUM_IN_LEVEL(fn) do { \ + _r.in.level = r->in.level;\ + NDR_SPOOLSS_PUSH_ENUM_IN(fn);\ +} while(0) + +#define NDR_SPOOLSS_PUSH_ENUM_OUT_LEVEL(fn) do { \ + DATA_BLOB _data_blob_info = data_blob_null;\ + struct ndr_push *_ndr_info = NULL;\ + _r.in.level = r->in.level;\ + _r.in.buffer = r->in.buffer;\ + _r.in.offered = r->in.offered;\ + _r.out.info = NULL;\ + _r.out.needed = r->out.needed;\ + _r.out.count = r->out.count;\ + _r.out.result = r->out.result;\ + if (r->out.info && *r->out.info && !r->in.buffer) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: *r->out.info but there's no r->in.buffer");\ + }\ + if (r->in.buffer) {\ + _ndr_info = ndr_push_init_ctx(ndr);\ + NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\ + _ndr_info->flags= ndr->flags;\ + if (r->out.info) {\ + struct ndr_push *_subndr_info;\ + struct __##fn __r;\ + __r.in.level = r->in.level;\ + __r.in.count = *r->out.count;\ + __r.out.info = *r->out.info;\ + NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered));\ + NDR_CHECK(ndr_push___##fn(_subndr_info, flags, &__r)); \ + NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered));\ + }\ + if (r->in.offered > _ndr_info->offset) {\ + uint32_t _padding_len = r->in.offered - _ndr_info->offset;\ + NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len));\ + } else if (r->in.offered < _ndr_info->offset) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of out buffer[%u]!",\ + (unsigned)r->in.offered, (unsigned)_ndr_info->offset);\ + }\ + _data_blob_info = ndr_push_blob(_ndr_info);\ + _r.out.info = &_data_blob_info;\ + }\ + NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\ +} while(0) + +#define NDR_SPOOLSS_PUSH_ENUM_OUT(fn) do { \ + DATA_BLOB _data_blob_info = data_blob_null;\ + struct ndr_push *_ndr_info = NULL;\ + _r.in.buffer = r->in.buffer;\ + _r.in.offered = r->in.offered;\ + _r.out.info = NULL;\ + _r.out.needed = r->out.needed;\ + _r.out.count = r->out.count;\ + _r.out.result = r->out.result;\ + if (r->out.info && *r->out.info && !r->in.buffer) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: *r->out.info but there's no r->in.buffer");\ + }\ + if (r->in.buffer) {\ + _ndr_info = ndr_push_init_ctx(ndr);\ + NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\ + _ndr_info->flags= ndr->flags;\ + if (r->out.info) {\ + struct ndr_push *_subndr_info;\ + struct __##fn __r;\ + __r.in.count = *r->out.count;\ + __r.out.info = *r->out.info;\ + NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered));\ + NDR_CHECK(ndr_push___##fn(_subndr_info, flags, &__r)); \ + NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered));\ + }\ + if (r->in.offered > _ndr_info->offset) {\ + uint32_t _padding_len = r->in.offered - _ndr_info->offset;\ + NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len));\ + } else if (r->in.offered < _ndr_info->offset) {\ + return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of out buffer[%u]!",\ + (unsigned)r->in.offered, (unsigned)_ndr_info->offset);\ + }\ + _data_blob_info = ndr_push_blob(_ndr_info);\ + _r.out.info = &_data_blob_info;\ + }\ + NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\ +} while(0) + +#define NDR_SPOOLSS_PUSH_ENUM_LEVEL(fn,in,out) do { \ + struct _##fn _r;\ + if (flags & NDR_IN) {\ + in;\ + NDR_SPOOLSS_PUSH_ENUM_IN_LEVEL(fn);\ + }\ + if (flags & NDR_OUT) {\ + out;\ + NDR_SPOOLSS_PUSH_ENUM_OUT_LEVEL(fn);\ + }\ +} while(0) + +#define NDR_SPOOLSS_PUSH_ENUM(fn,in,out) do { \ + struct _##fn _r;\ + if (flags & NDR_IN) {\ + in;\ + NDR_SPOOLSS_PUSH_ENUM_IN(fn);\ + }\ + if (flags & NDR_OUT) {\ + out;\ + NDR_SPOOLSS_PUSH_ENUM_OUT(fn);\ + }\ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn) do { \ + ZERO_STRUCT(r->out);\ + r->in.buffer = _r.in.buffer;\ + r->in.offered = _r.in.offered;\ + r->out.needed = _r.out.needed;\ + r->out.count = _r.out.count;\ + if (!r->in.buffer && r->in.offered != 0) {\ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] but there's no buffer",\ + (unsigned)r->in.offered);\ + } else if (r->in.buffer && r->in.buffer->length != r->in.offered) {\ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of r->in.buffer[%u]",\ + (unsigned)r->in.offered, (unsigned)r->in.buffer->length);\ + }\ + NDR_PULL_ALLOC(ndr, r->out.info);\ + ZERO_STRUCTP(r->out.info);\ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_IN(fn) do { \ + NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\ + NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn); \ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_IN_LEVEL(fn) do { \ + NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\ + r->in.level = _r.in.level;\ + NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn); \ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_OUT_LEVEL(fn) do { \ + _r.in.level = r->in.level;\ + _r.in.buffer = r->in.buffer;\ + _r.in.offered = r->in.offered;\ + _r.out.needed = r->out.needed;\ + _r.out.count = r->out.count;\ + NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\ + if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\ + NDR_PULL_ALLOC(ndr, r->out.info);\ + }\ + *r->out.info = NULL;\ + r->out.needed = _r.out.needed;\ + r->out.count = _r.out.count;\ + r->out.result = _r.out.result;\ + if (_r.out.info) {\ + struct ndr_pull *_ndr_info;\ + NDR_PULL_ALLOC(ndr, *r->out.info);\ + _ndr_info = ndr_pull_init_blob(_r.out.info, *r->out.info);\ + NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\ + _ndr_info->flags= ndr->flags;\ + if (r->in.offered != _ndr_info->data_size) {\ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]",\ + (unsigned)r->in.offered, (unsigned)_ndr_info->data_size);\ + }\ + if (*r->out.needed <= _ndr_info->data_size) {\ + struct __##fn __r;\ + __r.in.level = r->in.level;\ + __r.in.count = *r->out.count;\ + __r.out.info = NULL;\ + NDR_CHECK(ndr_pull___##fn(_ndr_info, flags, &__r));\ + *r->out.info = __r.out.info;\ + }\ + }\ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_OUT(fn) do { \ + _r.in.buffer = r->in.buffer;\ + _r.in.offered = r->in.offered;\ + _r.out.needed = r->out.needed;\ + _r.out.count = r->out.count;\ + NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\ + if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\ + NDR_PULL_ALLOC(ndr, r->out.info);\ + }\ + *r->out.info = NULL;\ + r->out.needed = _r.out.needed;\ + r->out.count = _r.out.count;\ + r->out.result = _r.out.result;\ + if (_r.out.info) {\ + struct ndr_pull *_ndr_info;\ + NDR_PULL_ALLOC(ndr, *r->out.info);\ + _ndr_info = ndr_pull_init_blob(_r.out.info, *r->out.info);\ + NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\ + _ndr_info->flags= ndr->flags;\ + if (r->in.offered != _ndr_info->data_size) {\ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\ + "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]",\ + (unsigned)r->in.offered, (unsigned)_ndr_info->data_size);\ + }\ + if (*r->out.needed <= _ndr_info->data_size) {\ + struct __##fn __r;\ + __r.in.count = *r->out.count;\ + __r.out.info = NULL;\ + NDR_CHECK(ndr_pull___##fn(_ndr_info, flags, &__r));\ + *r->out.info = __r.out.info;\ + }\ + }\ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM_LEVEL(fn,in,out) do { \ + struct _##fn _r;\ + if (flags & NDR_IN) {\ + out;\ + NDR_SPOOLSS_PULL_ENUM_IN_LEVEL(fn);\ + in;\ + }\ + if (flags & NDR_OUT) {\ + out;\ + NDR_SPOOLSS_PULL_ENUM_OUT_LEVEL(fn);\ + }\ +} while(0) + +#define NDR_SPOOLSS_PULL_ENUM(fn,in,out) do { \ + struct _##fn _r;\ + if (flags & NDR_IN) {\ + out;\ + NDR_SPOOLSS_PULL_ENUM_IN(fn);\ + in;\ + }\ + if (flags & NDR_OUT) {\ + out;\ + NDR_SPOOLSS_PULL_ENUM_OUT(fn);\ + }\ +} while(0) + +#define _NDR_CHECK_UINT32(call) do {\ + enum ndr_err_code _ndr_err; \ + _ndr_err = call; \ + if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \ + return 0; \ + }\ +} while (0) + +/* TODO: set _ndr_info->flags correct */ +#define NDR_SPOOLSS_SIZE_ENUM_LEVEL(fn) do { \ + struct __##fn __r;\ + DATA_BLOB _data_blob_info;\ + struct ndr_push *_ndr_info = ndr_push_init_ctx(mem_ctx);\ + if (!_ndr_info) return 0;\ + _ndr_info->flags|=LIBNDR_FLAG_NO_NDR_SIZE;\ + __r.in.level = level;\ + __r.in.count = count;\ + __r.out.info = info;\ + _NDR_CHECK_UINT32(ndr_push___##fn(_ndr_info, NDR_OUT, &__r)); \ + _data_blob_info = ndr_push_blob(_ndr_info);\ + return _data_blob_info.length;\ +} while(0) + +/* TODO: set _ndr_info->flags correct */ +#define NDR_SPOOLSS_SIZE_ENUM(fn) do { \ + struct __##fn __r;\ + DATA_BLOB _data_blob_info;\ + struct ndr_push *_ndr_info = ndr_push_init_ctx(mem_ctx);\ + if (!_ndr_info) return 0;\ + _ndr_info->flags|=LIBNDR_FLAG_NO_NDR_SIZE;\ + __r.in.count = count;\ + __r.out.info = info;\ + _NDR_CHECK_UINT32(ndr_push___##fn(_ndr_info, NDR_OUT, &__r)); \ + _data_blob_info = ndr_push_blob(_ndr_info);\ + return _data_blob_info.length;\ +} while(0) + + +/* + spoolss_EnumPrinters +*/ +enum ndr_err_code ndr_push_spoolss_EnumPrinters(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinters *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrinters,{ + _r.in.flags = r->in.flags; + _r.in.server = r->in.server; + },{ + _r.in.flags = r->in.flags; + _r.in.server = r->in.server; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPrinters(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinters *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrinters,{ + r->in.flags = _r.in.flags; + r->in.server = _r.in.server; + },{ + _r.in.flags = r->in.flags; + _r.in.server = r->in.server; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPrinters_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PrinterInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrinters); +} + +/* + spoolss_EnumJobs +*/ +enum ndr_err_code ndr_push_spoolss_EnumJobs(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumJobs *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumJobs,{ + _r.in.handle = r->in.handle; + _r.in.firstjob = r->in.firstjob; + _r.in.numjobs = r->in.numjobs; + },{ + _r.in.handle = r->in.handle; + _r.in.firstjob = r->in.firstjob; + _r.in.numjobs = r->in.numjobs; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumJobs(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumJobs *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumJobs,{ + r->in.handle = _r.in.handle; + r->in.firstjob = _r.in.firstjob; + r->in.numjobs = _r.in.numjobs; + },{ + _r.in.handle = r->in.handle; + _r.in.firstjob = r->in.firstjob; + _r.in.numjobs = r->in.numjobs; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumJobs_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_JobInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumJobs); +} + +/* + spoolss_EnumPrinterDrivers +*/ +enum ndr_err_code ndr_push_spoolss_EnumPrinterDrivers(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDrivers *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrinterDrivers,{ + _r.in.server = r->in.server; + _r.in.environment = r->in.environment; + },{ + _r.in.server = r->in.server; + _r.in.environment = r->in.environment; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPrinterDrivers(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDrivers *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrinterDrivers,{ + r->in.server = _r.in.server; + r->in.environment = _r.in.environment; + },{ + _r.in.server = r->in.server; + _r.in.environment = r->in.environment; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPrinterDrivers_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_DriverInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers); +} + +/* + spoolss_EnumForms +*/ +enum ndr_err_code ndr_push_spoolss_EnumForms(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumForms *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumForms,{ + _r.in.handle = r->in.handle; + },{ + _r.in.handle = r->in.handle; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumForms(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumForms *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumForms,{ + r->in.handle = _r.in.handle; + },{ + _r.in.handle = r->in.handle; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumForms_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_FormInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumForms); +} + +/* + spoolss_EnumPorts +*/ +enum ndr_err_code ndr_push_spoolss_EnumPorts(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPorts *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPorts,{ + _r.in.servername= r->in.servername; + },{ + _r.in.servername= r->in.servername; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPorts(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPorts *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPorts,{ + r->in.servername= _r.in.servername; + },{ + _r.in.servername= r->in.servername; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPorts_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PortInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPorts); +} + +/* + spoolss_EnumMonitors +*/ +enum ndr_err_code ndr_push_spoolss_EnumMonitors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumMonitors *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumMonitors,{ + _r.in.servername= r->in.servername; + },{ + _r.in.servername= r->in.servername; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumMonitors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumMonitors *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumMonitors,{ + r->in.servername= _r.in.servername; + },{ + _r.in.servername= r->in.servername; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumMonitors_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_MonitorInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumMonitors); +} + +/* + spoolss_EnumPrintProcessors +*/ +enum ndr_err_code ndr_push_spoolss_EnumPrintProcessors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessors *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrintProcessors,{ + _r.in.servername = r->in.servername; + _r.in.environment = r->in.environment; + },{ + _r.in.servername = r->in.servername; + _r.in.environment = r->in.environment; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessors *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrintProcessors,{ + r->in.servername = _r.in.servername; + r->in.environment = _r.in.environment; + },{ + _r.in.servername = r->in.servername; + _r.in.environment = r->in.environment; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPrintProcessors_info(TALLOC_CTX *mem_ctx, + uint32_t level, uint32_t count, union spoolss_PrintProcessorInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors); +} + +/* + spoolss_EnumPrintProcessors +*/ +enum ndr_err_code ndr_push_spoolss_EnumPrintProcessorDataTypes(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessorDataTypes *r) +{ + NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes,{ + _r.in.servername = r->in.servername; + _r.in.print_processor_name = r->in.print_processor_name; + },{ + _r.in.servername = r->in.servername; + _r.in.print_processor_name = r->in.print_processor_name; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessorDataTypes(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessorDataTypes *r) +{ + NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes,{ + r->in.servername = _r.in.servername; + r->in.print_processor_name = _r.in.print_processor_name; + },{ + _r.in.servername = r->in.servername; + _r.in.print_processor_name = r->in.print_processor_name; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPrintProcessorDataTypes_info(TALLOC_CTX *mem_ctx, + uint32_t level, uint32_t count, union spoolss_PrintProcDataTypesInfo *info) +{ + NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes); +} + +/* + spoolss_EnumPerMachineConnections +*/ +enum ndr_err_code ndr_push_spoolss_EnumPerMachineConnections(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPerMachineConnections *r) +{ + NDR_SPOOLSS_PUSH_ENUM(spoolss_EnumPerMachineConnections,{ + _r.in.server = r->in.server; + },{ + _r.in.server = r->in.server; + }); + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPerMachineConnections(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPerMachineConnections *r) +{ + NDR_SPOOLSS_PULL_ENUM(spoolss_EnumPerMachineConnections,{ + r->in.server = _r.in.server; + },{ + _r.in.server = r->in.server; + }); + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPerMachineConnections_info(TALLOC_CTX *mem_ctx, uint32_t count, struct spoolss_PrinterInfo4 *info) +{ + NDR_SPOOLSS_SIZE_ENUM(spoolss_EnumPerMachineConnections); +} + +/* + spoolss_EnumPrinterDataEx +*/ + +enum ndr_err_code ndr_push_spoolss_EnumPrinterDataEx(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDataEx *r) +{ + struct _spoolss_EnumPrinterDataEx _r; + if (flags & NDR_IN) { + _r.in.handle = r->in.handle; + _r.in.key_name = r->in.key_name; + _r.in.offered = r->in.offered; + NDR_CHECK(ndr_push__spoolss_EnumPrinterDataEx(ndr, flags, &_r)); + } + if (flags & NDR_OUT) { + struct ndr_push *_ndr_info; + _r.in.handle = r->in.handle; + _r.in.key_name = r->in.key_name; + _r.in.offered = r->in.offered; + _r.out.count = r->out.count; + _r.out.needed = r->out.needed; + _r.out.result = r->out.result; + _r.out.info = data_blob(NULL, 0); + if (r->in.offered >= *r->out.needed) { + struct ndr_push *_subndr_info; + struct __spoolss_EnumPrinterDataEx __r; + _ndr_info = ndr_push_init_ctx(ndr); + NDR_ERR_HAVE_NO_MEMORY(_ndr_info); + _ndr_info->flags= ndr->flags; + __r.in.count = *r->out.count; + __r.out.info = *r->out.info; + NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered)); + NDR_CHECK(ndr_push___spoolss_EnumPrinterDataEx(_subndr_info, flags, &__r)); + NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered)); + if (r->in.offered > _ndr_info->offset) { + uint32_t _padding_len = r->in.offered - _ndr_info->offset; + NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len)); + } + _r.out.info = ndr_push_blob(_ndr_info); + } + NDR_CHECK(ndr_push__spoolss_EnumPrinterDataEx(ndr, flags, &_r)); + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_pull_spoolss_EnumPrinterDataEx(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDataEx *r) +{ + struct _spoolss_EnumPrinterDataEx _r; + if (flags & NDR_IN) { + _r.in.handle = r->in.handle; + _r.in.key_name = r->in.key_name; + ZERO_STRUCT(r->out); + NDR_CHECK(ndr_pull__spoolss_EnumPrinterDataEx(ndr, flags, &_r)); + r->in.handle = _r.in.handle; + r->in.key_name = _r.in.key_name; + r->in.offered = _r.in.offered; + r->out.needed = _r.out.needed; + r->out.count = _r.out.count; + NDR_PULL_ALLOC(ndr, r->out.info); + ZERO_STRUCTP(r->out.info); + } + if (flags & NDR_OUT) { + _r.in.handle = r->in.handle; + _r.in.key_name = r->in.key_name; + _r.in.offered = r->in.offered; + _r.out.count = r->out.count; + _r.out.needed = r->out.needed; + NDR_CHECK(ndr_pull__spoolss_EnumPrinterDataEx(ndr, flags, &_r)); + if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) { + NDR_PULL_ALLOC(ndr, r->out.info); + } + *r->out.info = NULL; + r->out.needed = _r.out.needed; + r->out.count = _r.out.count; + r->out.result = _r.out.result; + if (_r.out.info.length) { + struct ndr_pull *_ndr_info; + NDR_PULL_ALLOC(ndr, *r->out.info); + _ndr_info = ndr_pull_init_blob(&_r.out.info, *r->out.info); + NDR_ERR_HAVE_NO_MEMORY(_ndr_info); + _ndr_info->flags= ndr->flags; + if (r->in.offered != _ndr_info->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]", + (unsigned)r->in.offered, (unsigned)_ndr_info->data_size); + } + if (*r->out.needed <= _ndr_info->data_size) { + struct __spoolss_EnumPrinterDataEx __r; + __r.in.count = *r->out.count; + __r.out.info = NULL; + NDR_CHECK(ndr_pull___spoolss_EnumPrinterDataEx(_ndr_info, flags, &__r)); + *r->out.info = __r.out.info; + } + } + } + return NDR_ERR_SUCCESS; +} + +uint32_t ndr_size_spoolss_EnumPrinterDataEx_info(TALLOC_CTX *mem_ctx, + uint32_t count, struct spoolss_PrinterEnumValues *info) +{ + NDR_SPOOLSS_SIZE_ENUM(spoolss_EnumPrinterDataEx); +} + +uint32_t _ndr_size_spoolss_DeviceMode(struct spoolss_DeviceMode *devmode, libndr_flags flags) +{ + if (!devmode) return 0; + return ndr_size_spoolss_DeviceMode(devmode, flags); +} + +_PUBLIC_ size_t ndr_size_spoolss_StringArray(const struct spoolss_StringArray *r, libndr_flags flags) +{ + if (!r) { + return 4; + } + + return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_spoolss_StringArray); +} + +/* hand marshall as pidl cannot (yet) generate a relative pointer to a fixed array of + * structs */ + +_PUBLIC_ enum ndr_err_code ndr_push_spoolss_DriverInfo101(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_DriverInfo101 *r) +{ + uint32_t cntr_file_info_1; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 8)); + NDR_CHECK(ndr_push_spoolss_DriverOSVersion(ndr, NDR_SCALARS, r->version)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->driver_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->architecture)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->file_info)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->file_count)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->monitor_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->default_datatype)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string_array = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->previous_names)); + ndr->flags = _flags_save_string_array; + } + NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->driver_date)); + NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->driver_version)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->manufacturer_name)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->manufacturer_url)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->hardware_id)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->provider)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_push_trailer_align(ndr, 8)); + } + if (ndr_flags & NDR_BUFFERS) { + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->driver_name) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->driver_name)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->driver_name)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->driver_name)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->architecture) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->architecture)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->architecture)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->architecture)); + } + ndr->flags = _flags_save_string; + } + if (r->file_info) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->file_info)); +#if 0 + NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->file_count)); +#endif + for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) { + NDR_CHECK(ndr_push_spoolss_DriverFileInfo(ndr, NDR_SCALARS, &r->file_info[cntr_file_info_1])); + } + for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) { + NDR_CHECK(ndr_push_spoolss_DriverFileInfo(ndr, NDR_BUFFERS, &r->file_info[cntr_file_info_1])); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->file_info)); + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->monitor_name) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->monitor_name)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->monitor_name)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->monitor_name)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->default_datatype) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->default_datatype)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->default_datatype)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->default_datatype)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string_array = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->previous_names) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->previous_names)); + NDR_CHECK(ndr_push_string_array(ndr, NDR_SCALARS, r->previous_names)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->previous_names)); + } + ndr->flags = _flags_save_string_array; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->manufacturer_name) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->manufacturer_name)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->manufacturer_name)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->manufacturer_name)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->manufacturer_url) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->manufacturer_url)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->manufacturer_url)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->manufacturer_url)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->hardware_id) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->hardware_id)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->hardware_id)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->hardware_id)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->provider) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->provider)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->provider)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->provider)); + } + ndr->flags = _flags_save_string; + } + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_spoolss_DriverInfo101(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct spoolss_DriverInfo101 *r) +{ + uint32_t _ptr_driver_name; + TALLOC_CTX *_mem_save_driver_name_0; + uint32_t _ptr_architecture; + TALLOC_CTX *_mem_save_architecture_0; + uint32_t _ptr_file_info; + uint32_t cntr_file_info_1; + TALLOC_CTX *_mem_save_file_info_0; + TALLOC_CTX *_mem_save_file_info_1; + uint32_t _ptr_monitor_name; + TALLOC_CTX *_mem_save_monitor_name_0; + uint32_t _ptr_default_datatype; + TALLOC_CTX *_mem_save_default_datatype_0; + uint32_t _ptr_previous_names; + TALLOC_CTX *_mem_save_previous_names_0; + uint32_t _ptr_manufacturer_name; + TALLOC_CTX *_mem_save_manufacturer_name_0; + uint32_t _ptr_manufacturer_url; + TALLOC_CTX *_mem_save_manufacturer_url_0; + uint32_t _ptr_hardware_id; + TALLOC_CTX *_mem_save_hardware_id_0; + uint32_t _ptr_provider; + TALLOC_CTX *_mem_save_provider_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 8)); + NDR_CHECK(ndr_pull_spoolss_DriverOSVersion(ndr, NDR_SCALARS, &r->version)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_driver_name)); + if (_ptr_driver_name) { + NDR_PULL_ALLOC(ndr, r->driver_name); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->driver_name, _ptr_driver_name)); + } else { + r->driver_name = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_architecture)); + if (_ptr_architecture) { + NDR_PULL_ALLOC(ndr, r->architecture); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->architecture, _ptr_architecture)); + } else { + r->architecture = NULL; + } + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_file_info)); + if (_ptr_file_info) { + NDR_PULL_ALLOC(ndr, r->file_info); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->file_info, _ptr_file_info)); + } else { + r->file_info = NULL; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->file_count)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_monitor_name)); + if (_ptr_monitor_name) { + NDR_PULL_ALLOC(ndr, r->monitor_name); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->monitor_name, _ptr_monitor_name)); + } else { + r->monitor_name = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_default_datatype)); + if (_ptr_default_datatype) { + NDR_PULL_ALLOC(ndr, r->default_datatype); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->default_datatype, _ptr_default_datatype)); + } else { + r->default_datatype = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string_array = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_previous_names)); + if (_ptr_previous_names) { + NDR_PULL_ALLOC(ndr, r->previous_names); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->previous_names, _ptr_previous_names)); + } else { + r->previous_names = NULL; + } + ndr->flags = _flags_save_string_array; + } + NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->driver_date)); + NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->driver_version)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_manufacturer_name)); + if (_ptr_manufacturer_name) { + NDR_PULL_ALLOC(ndr, r->manufacturer_name); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->manufacturer_name, _ptr_manufacturer_name)); + } else { + r->manufacturer_name = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_manufacturer_url)); + if (_ptr_manufacturer_url) { + NDR_PULL_ALLOC(ndr, r->manufacturer_url); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->manufacturer_url, _ptr_manufacturer_url)); + } else { + r->manufacturer_url = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hardware_id)); + if (_ptr_hardware_id) { + NDR_PULL_ALLOC(ndr, r->hardware_id); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->hardware_id, _ptr_hardware_id)); + } else { + r->hardware_id = NULL; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_provider)); + if (_ptr_provider) { + NDR_PULL_ALLOC(ndr, r->provider); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->provider, _ptr_provider)); + } else { + r->provider = NULL; + } + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 8)); + } + if (ndr_flags & NDR_BUFFERS) { + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->driver_name) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->driver_name)); + _mem_save_driver_name_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->driver_name, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->driver_name)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_driver_name_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->architecture) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->architecture)); + _mem_save_architecture_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->architecture, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->architecture)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_architecture_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + if (r->file_info) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->file_info)); + _mem_save_file_info_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->file_info, 0); +#if 0 + NDR_CHECK(ndr_pull_array_size(ndr, &r->file_info)); +#else + NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list, &r->file_info, r->file_count)); +#endif + NDR_PULL_ALLOC_N(ndr, r->file_info, r->file_count); + _mem_save_file_info_1 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->file_info, 0); + for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) { + NDR_CHECK(ndr_pull_spoolss_DriverFileInfo(ndr, NDR_SCALARS, &r->file_info[cntr_file_info_1])); + } + for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) { + NDR_CHECK(ndr_pull_spoolss_DriverFileInfo(ndr, NDR_BUFFERS, &r->file_info[cntr_file_info_1])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_file_info_1, 0); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_file_info_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->monitor_name) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->monitor_name)); + _mem_save_monitor_name_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->monitor_name, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->monitor_name)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_monitor_name_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->default_datatype) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->default_datatype)); + _mem_save_default_datatype_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->default_datatype, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->default_datatype)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_default_datatype_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string_array = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->previous_names) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->previous_names)); + _mem_save_previous_names_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->previous_names, 0); + NDR_CHECK(ndr_pull_string_array(ndr, NDR_SCALARS, &r->previous_names)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_previous_names_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string_array; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->manufacturer_name) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->manufacturer_name)); + _mem_save_manufacturer_name_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->manufacturer_name, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->manufacturer_name)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_manufacturer_name_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->manufacturer_url) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->manufacturer_url)); + _mem_save_manufacturer_url_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->manufacturer_url, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->manufacturer_url)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_manufacturer_url_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->hardware_id) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->hardware_id)); + _mem_save_hardware_id_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->hardware_id, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->hardware_id)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hardware_id_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->provider) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->provider)); + _mem_save_provider_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->provider, 0); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->provider)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_provider_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + ndr->flags = _flags_save_string; + } + if (r->file_info) { + NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->file_info, r->file_count)); + } + } + return NDR_ERR_SUCCESS; +} + +void ndr_print_spoolss_Field(struct ndr_print *ndr, const char *name, const union spoolss_Field *r) +{ + int level; + level = ndr_print_steal_switch_value(ndr, r); + ndr_print_union(ndr, name, level, "spoolss_Field"); + switch (level) { + case PRINTER_NOTIFY_TYPE: + ndr_print_spoolss_PrintNotifyField(ndr, "field", r->field); + break; + + case JOB_NOTIFY_TYPE: + ndr_print_spoolss_JobNotifyField(ndr, "field", r->field); + break; + + default: + ndr_print_uint16(ndr, "field", r->field); + break; + + } +} + +_PUBLIC_ size_t ndr_size_spoolss_PrinterData(const union spoolss_PrinterData *r, uint32_t level, libndr_flags flags) +{ + if (!r) { + return 0; + } + return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_spoolss_PrinterData); +} + +void ndr_print_spoolss_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r) +{ + ndr_print_security_descriptor(ndr, name, r); +} + +enum ndr_err_code ndr_pull_spoolss_security_descriptor(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_descriptor *r) +{ + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_RELATIVE_REVERSE); + NDR_CHECK(ndr_pull_security_descriptor(ndr, ndr_flags, r)); + ndr->flags = _flags_save_STRUCT; + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_spoolss_security_descriptor(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_descriptor *r) +{ + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NO_RELATIVE_REVERSE); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + NDR_CHECK(ndr_push_security_descriptor_revision(ndr, NDR_SCALARS, r->revision)); + NDR_CHECK(ndr_push_security_descriptor_type(ndr, NDR_SCALARS, r->type)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->owner_sid)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->group_sid)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sacl)); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->dacl)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->sacl) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sacl)); + NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->sacl)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sacl)); + } + if (r->dacl) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->dacl)); + NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->dacl)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->dacl)); + } + if (r->owner_sid) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->owner_sid)); + NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, r->owner_sid)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->owner_sid)); + } + if (r->group_sid) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->group_sid)); + NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, r->group_sid)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->group_sid)); + } + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_spoolss_PrinterInfo2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_PrinterInfo2 *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 5)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->servername)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->printername)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sharename)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->portname)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->drivername)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->comment)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->location)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_spoolss_DeviceMode = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->devmode)); + ndr->flags = _flags_save_spoolss_DeviceMode; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sepfile)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->printprocessor)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->datatype)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->parameters)); + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_spoolss_security_descriptor = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + NDR_CHECK(ndr_push_relative_ptr1(ndr, r->secdesc)); + ndr->flags = _flags_save_spoolss_security_descriptor; + } + NDR_CHECK(ndr_push_spoolss_PrinterAttributes(ndr, NDR_SCALARS, r->attributes)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->priority)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->defaultpriority)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->starttime)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->untiltime)); + NDR_CHECK(ndr_push_spoolss_PrinterStatus(ndr, NDR_SCALARS, r->status)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->cjobs)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->averageppm)); + NDR_CHECK(ndr_push_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->servername) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->servername)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->servername)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->servername)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->printername) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->printername)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->printername)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->printername)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->sharename) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sharename)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sharename)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sharename)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->portname) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->portname)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->portname)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->portname)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->drivername) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->drivername)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->drivername)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->drivername)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->comment) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->comment)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->comment)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->comment)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->location) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->location)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->location)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->location)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->sepfile) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sepfile)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sepfile)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sepfile)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->printprocessor) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->printprocessor)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->printprocessor)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->printprocessor)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->datatype) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->datatype)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->datatype)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->datatype)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM); + if (r->parameters) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->parameters)); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->parameters)); + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->parameters)); + } + ndr->flags = _flags_save_string; + } + { + libndr_flags _flags_save_spoolss_DeviceMode = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + if (r->devmode) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->devmode)); + { + struct ndr_push *_ndr_devmode; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_devmode, 0, -1)); + NDR_CHECK(ndr_push_spoolss_DeviceMode(_ndr_devmode, NDR_SCALARS, r->devmode)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_devmode, 0, -1)); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->devmode)); + } + ndr->flags = _flags_save_spoolss_DeviceMode; + } + { + libndr_flags _flags_save_spoolss_security_descriptor = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4); + if (r->secdesc) { + NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->secdesc)); + { + struct ndr_push *_ndr_secdesc; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_secdesc, 0, -1)); + NDR_CHECK(ndr_push_spoolss_security_descriptor(_ndr_secdesc, NDR_SCALARS|NDR_BUFFERS, r->secdesc)); + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_secdesc, 0, -1)); + } + NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->secdesc)); + } + ndr->flags = _flags_save_spoolss_security_descriptor; + } + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_spoolss_Time(struct ndr_print *ndr, const char *name, const struct spoolss_Time *r) +{ + struct tm tm; + time_t t; + char *str; + + tm.tm_sec = r->second; + tm.tm_min = r->minute; + tm.tm_hour = r->hour; + tm.tm_mday = r->day; + tm.tm_mon = r->month - 1; + tm.tm_year = r->year - 1900; + tm.tm_wday = r->day_of_week; + tm.tm_yday = 0; + tm.tm_isdst = -1; + + t = mktime(&tm); + + str = timestring(ndr, t); + + ndr_print_struct(ndr, name, "spoolss_Time"); + ndr->depth++; + ndr_print_string(ndr, "", str); + ndr->depth--; + talloc_free(str); +} + +_PUBLIC_ libndr_flags ndr_spoolss_PrinterEnumValues_align(enum winreg_Type type) +{ + switch(type) { + case REG_NONE: + return 0; + case REG_SZ: + return LIBNDR_FLAG_ALIGN2; + case REG_EXPAND_SZ: + return LIBNDR_FLAG_ALIGN2; + case REG_BINARY: + return 0; + case REG_DWORD: + return LIBNDR_FLAG_ALIGN4; + case REG_DWORD_BIG_ENDIAN: + return LIBNDR_FLAG_ALIGN4; + case REG_LINK: + return 0; + case REG_MULTI_SZ: + return LIBNDR_FLAG_ALIGN2; + case REG_RESOURCE_LIST: + return LIBNDR_FLAG_ALIGN2; + case REG_FULL_RESOURCE_DESCRIPTOR: + return LIBNDR_FLAG_ALIGN4; + case REG_RESOURCE_REQUIREMENTS_LIST: + return LIBNDR_FLAG_ALIGN2; + case REG_QWORD: + return LIBNDR_FLAG_ALIGN8; + } + + return 0; +} diff --git a/librpc/ndr/ndr_spoolss_buf.h b/librpc/ndr/ndr_spoolss_buf.h new file mode 100644 index 0000000..aeb071d --- /dev/null +++ b/librpc/ndr/ndr_spoolss_buf.h @@ -0,0 +1,84 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling spoolss subcontext buffer structures + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Tim Potter 2003 + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +#ifndef ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__ +#define ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +/* this file contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + + +/* The following definitions come from /space/src/samba/SOURCES/samba.git/source3/../source4/librpc/ndr/ndr_spoolss_buf.c */ + +enum ndr_err_code ndr_push_spoolss_EnumPrinters(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinters *r); +enum ndr_err_code ndr_pull_spoolss_EnumPrinters(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinters *r); +uint32_t ndr_size_spoolss_EnumPrinters_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PrinterInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumJobs(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumJobs *r); +enum ndr_err_code ndr_pull_spoolss_EnumJobs(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumJobs *r); +uint32_t ndr_size_spoolss_EnumJobs_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_JobInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumPrinterDrivers(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDrivers *r); +enum ndr_err_code ndr_pull_spoolss_EnumPrinterDrivers(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDrivers *r); +uint32_t ndr_size_spoolss_EnumPrinterDrivers_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_DriverInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumForms(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumForms *r); +enum ndr_err_code ndr_pull_spoolss_EnumForms(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumForms *r); +uint32_t ndr_size_spoolss_EnumForms_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_FormInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumPorts(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPorts *r); +enum ndr_err_code ndr_pull_spoolss_EnumPorts(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPorts *r); +uint32_t ndr_size_spoolss_EnumPorts_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PortInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumMonitors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumMonitors *r); +enum ndr_err_code ndr_pull_spoolss_EnumMonitors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumMonitors *r); +uint32_t ndr_size_spoolss_EnumMonitors_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_MonitorInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumPrintProcessors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessors *r); +enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessors *r); +uint32_t ndr_size_spoolss_EnumPrintProcessors_info(TALLOC_CTX *mem_ctx, + uint32_t level, uint32_t count, union spoolss_PrintProcessorInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumPrintProcessorDataTypes(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessorDataTypes *r); +enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessorDataTypes(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessorDataTypes *r); +uint32_t ndr_size_spoolss_EnumPrintProcessorDataTypes_info(TALLOC_CTX *mem_ctx, + uint32_t level, uint32_t count, union spoolss_PrintProcDataTypesInfo *info); +enum ndr_err_code ndr_push_spoolss_EnumPrinterDataEx(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDataEx *r); +enum ndr_err_code ndr_pull_spoolss_EnumPrinterDataEx(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDataEx *r); +uint32_t ndr_size_spoolss_EnumPrinterDataEx_info(TALLOC_CTX *mem_ctx, + uint32_t count, struct spoolss_PrinterEnumValues *info); +uint32_t _ndr_size_spoolss_DeviceMode(struct spoolss_DeviceMode *devmode, libndr_flags flags); +size_t ndr_size_spoolss_StringArray(const struct spoolss_StringArray *r, libndr_flags flags); +_PUBLIC_ enum ndr_err_code ndr_push_spoolss_DriverInfo101(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_DriverInfo101 *r); +_PUBLIC_ enum ndr_err_code ndr_pull_spoolss_DriverInfo101(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct spoolss_DriverInfo101 *r); +void ndr_print_spoolss_Field(struct ndr_print *ndr, const char *name, const union spoolss_Field *r); +size_t ndr_size_spoolss_PrinterData(const union spoolss_PrinterData *r, uint32_t level, libndr_flags flags); +void ndr_print_spoolss_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r); +enum ndr_err_code ndr_pull_spoolss_security_descriptor(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_descriptor *r); +enum ndr_err_code ndr_push_spoolss_security_descriptor(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_descriptor *r); +_PUBLIC_ void ndr_print_spoolss_Time(struct ndr_print *ndr, const char *name, const struct spoolss_Time *r); +_PUBLIC_ libndr_flags ndr_spoolss_PrinterEnumValues_align(enum winreg_Type type); + +uint32_t ndr_size_spoolss_EnumPerMachineConnections_info(TALLOC_CTX *mem_ctx, uint32_t count, struct spoolss_PrinterInfo4 *info); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__ */ diff --git a/librpc/ndr/ndr_string.c b/librpc/ndr/ndr_string.c new file mode 100644 index 0000000..323886b --- /dev/null +++ b/librpc/ndr/ndr_string.c @@ -0,0 +1,1109 @@ +/* + 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 . +*/ + +#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, ndr_flags_type ndr_flags, const char **s) +{ + char *as=NULL; + uint32_t len1, ofs, len2; + uint16_t len3; + size_t conv_src_len = 0, converted_size; + int do_convert = 1, chset = CH_UTF16; + unsigned byte_mul = 2; + libndr_flags flags = ndr->flags; + unsigned c_len_term = 0; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + chset = CH_UTF16BE; + } + + /* + * We will check this flag, but from the unmodified + * ndr->flags, so just remove it from flags + */ + flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL; + + switch (flags & LIBNDR_ENCODING_FLAGS) { + case 0: + break; + + case LIBNDR_FLAG_STR_ASCII: + chset = CH_DOS; + byte_mul = 1; + break; + + case LIBNDR_FLAG_STR_UTF8: + chset = CH_UTF8; + byte_mul = 1; + break; + + case LIBNDR_FLAG_STR_RAW8: + do_convert = 0; + byte_mul = 1; + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + flags &= ~LIBNDR_ENCODING_FLAGS; + + 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%"PRI_LIBNDR_FLAGS"\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=%"PRIu32" ofs=%"PRIu32" len2=%"PRIu32"\n", + len1, ofs, len2); + } else if (len1 != len2) { + DEBUG(6,("len1[%"PRIu32"] != len2[%"PRIu32"]\n", len1, len2)); + } + conv_src_len = len2 + c_len_term; + break; + + case LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + conv_src_len = len1 + c_len_term; + break; + + case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + conv_src_len = len1; + byte_mul = 1; /* the length is now absolute */ + 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%"PRI_LIBNDR_FLAGS"\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + conv_src_len = len1 + c_len_term; + break; + + case LIBNDR_FLAG_STR_SIZE2: + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + conv_src_len = len3 + c_len_term; + break; + + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + conv_src_len = len3; + byte_mul = 1; /* the length is now absolute */ + break; + + case LIBNDR_FLAG_STR_NULLTERM: + /* + * We ensure that conv_src_len cannot equal 0 by + * requiring that there be enough bytes for at least + * the NULL terminator + */ + if (byte_mul == 1) { + NDR_PULL_NEED_BYTES(ndr, 1); + conv_src_len = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); + } else { + NDR_PULL_NEED_BYTES(ndr, 2); + conv_src_len = utf16_null_terminated_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); + } + byte_mul = 1; /* the length is now absolute */ + break; + + case LIBNDR_FLAG_STR_NOTERM: + if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + conv_src_len = ndr->data_size - ndr->offset; + byte_mul = 1; /* the length is now absolute */ + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + NDR_PULL_NEED_BYTES(ndr, conv_src_len * byte_mul); + if (conv_src_len == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + converted_size = 0; + if (!as) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "Failed to talloc_strndup() in zero-length ndr_pull_string()"); + } + } else { + if (!do_convert) { + as = talloc_strndup(ndr->current_mem_ctx, + (char *)ndr->data + ndr->offset, + conv_src_len); + if (!as) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "Failed to talloc_strndup() in RAW8 ndr_pull_string()"); + } + converted_size = MIN(strlen(as)+1, conv_src_len); + } else if (!convert_string_talloc(ndr->current_mem_ctx, chset, + CH_UNIX, ndr->data + ndr->offset, + conv_src_len * byte_mul, + &as, + &converted_size)) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags); + } + } + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (converted_size > 0 && as[converted_size-1] == '\0') { + DEBUG(6,("short string '%s', sent with NULL termination despite NOTERM flag in IDL\n", as)); + } + /* + * We check the original ndr->flags as it has already + * been removed from the local variable flags + */ + if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) { + size_t strlen_of_unix_string = strlen(as); + if (strlen_of_unix_string != converted_size) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Embedded NUL at position %zu in " + "converted string " + "(and therefore source string) " + "despite " + "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n", + strlen_of_unix_string); + } + } + } else { + /* + * We check the original ndr->flags as it has already + * been removed from the local variable flags + */ + if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) { + size_t strlen_of_unix_string = strlen(as); + if (converted_size > 0 && strlen_of_unix_string != converted_size - 1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Embedded NUL at position %zu in " + "converted string " + "(and therefore source string) " + "despite " + "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n", + strlen_of_unix_string); + } + } + if (converted_size > 0 && as[converted_size-1] != '\0') { + DEBUG(6,("long string '%s', sent without NULL termination (which was expected)\n", as)); + } + } + + NDR_CHECK(ndr_pull_advance(ndr, conv_src_len * byte_mul)); + *s = as; + + return NDR_ERR_SUCCESS; +} + + +/** + push a general string onto the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *s) +{ + ssize_t s_len, c_len; + size_t d_len; + int do_convert = 1, chset = CH_UTF16; + libndr_flags flags = ndr->flags; + unsigned byte_mul = 2; + const uint8_t *dest = NULL; + uint8_t *dest_to_free = NULL; + static const uint8_t null_byte[] = {0}; + enum ndr_err_code ndr_err = NDR_ERR_SUCCESS; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + chset = CH_UTF16BE; + } + + s_len = s?strlen(s):0; + + /* + * We will check this flag, but from the unmodified + * ndr->flags, so just remove it from flags + */ + flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL; + + switch (flags & LIBNDR_ENCODING_FLAGS) { + case 0: + break; + + case LIBNDR_FLAG_STR_ASCII: + chset = CH_DOS; + byte_mul = 1; + break; + + case LIBNDR_FLAG_STR_UTF8: + chset = CH_UTF8; + byte_mul = 1; + break; + + case LIBNDR_FLAG_STR_RAW8: + do_convert = 0; + byte_mul = 1; + break; + + default: + return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + flags &= ~LIBNDR_ENCODING_FLAGS; + + flags &= ~LIBNDR_FLAG_STR_CONFORMANT; + + if (!(flags & LIBNDR_FLAG_STR_NOTERM)) { + s_len++; + } + + if (s_len == 0) { + d_len = 0; + dest = null_byte; + } else if (!do_convert) { + d_len = s_len; + dest = (const uint8_t *)s; + } else { + bool ok; + + ok = convert_string_talloc(ndr, CH_UNIX, chset, s, s_len, + &dest_to_free, &d_len); + if (!ok) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character push conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags); + } + + dest = dest_to_free; + } + + 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) { + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + + case LIBNDR_FLAG_STR_LEN4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + + case LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + + case LIBNDR_FLAG_STR_SIZE2: + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: + ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, c_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + + case LIBNDR_FLAG_STR_NULLTERM: + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + + default: + if (ndr->flags & LIBNDR_FLAG_REMAINING) { + ndr_err = ndr_push_bytes(ndr, dest, d_len); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto out; + } + break; + } + + ndr_err = ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n", + ndr->flags & LIBNDR_STRING_FLAGS); + goto out; + } + +out: + talloc_free(dest_to_free); + return ndr_err; +} + +/** + 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; + libndr_flags flags = ndr->flags; + unsigned byte_mul = 2; + unsigned c_len_term = 1; + + if (flags & LIBNDR_FLAG_STR_RAW8) { + c_len = s?strlen(s):0; + } else { + c_len = s?strlen_m(s):0; + } + + if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_RAW8|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 (NDR_HIDE_SECRET(ndr)) { + ndr->print(ndr, "%-25s: ", name); + return; + } + 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, ndr_flags_type flags) +{ + /* FIXME: Is this correct for all strings ? */ + if(!(*string)) return ret; + return ret+strlen(*string)+1; +} + +/** + pull a UTF‐16 string from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_u16string(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + const unsigned char **s) +{ + unsigned char *as = NULL; + const char *const src_str = (char *)ndr->data + ndr->offset; + size_t src_len = 0; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + /* + * It isn’t clear how this type should be encoded in a + * big‐endian context. + */ + return ndr_pull_error( + ndr, + NDR_ERR_STRING, + "u16string does not support big‐endian encoding\n"); + } + + if (ndr->flags & LIBNDR_ENCODING_FLAGS) { + return ndr_pull_error( + ndr, + NDR_ERR_STRING, + "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS + " passed to ndr_pull_u16string()\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + switch (ndr->flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_NULLTERM: + /* + * We ensure that src_len cannot equal 0 by + * requiring that there be enough bytes for at least + * the NULL terminator + */ + NDR_PULL_NEED_BYTES(ndr, 2); + src_len = utf16_null_terminated_len_n(src_str, + ndr->data_size - + ndr->offset); + break; + + default: + return ndr_pull_error( + ndr, + NDR_ERR_STRING, + "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS + " passed to ndr_pull_u16string()\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + NDR_PULL_NEED_BYTES(ndr, src_len); + as = talloc_utf16_strlendup(ndr->current_mem_ctx, + src_str, + src_len); + if (as == NULL) { + return ndr_pull_error(ndr, + NDR_ERR_ALLOC, + "Failed to talloc_utf16_strlendup() in " + "ndr_pull_u16string()"); + } + + NDR_CHECK(ndr_pull_advance(ndr, src_len)); + *s = as; + + return NDR_ERR_SUCCESS; +} + +/** + push a UTF‐16 string onto the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_push_u16string(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const unsigned char *s) +{ + size_t s_len; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr)) { + /* + * It isn’t clear how this type should be encoded in a + * big‐endian context. + */ + return ndr_push_error( + ndr, + NDR_ERR_STRING, + "u16string does not support big‐endian encoding\n"); + } + + if (s == NULL) { + return ndr_push_error( + ndr, + NDR_ERR_INVALID_POINTER, + "NULL pointer passed to ndr_push_u16string()"); + } + + s_len = utf16_null_terminated_len(s); + if (s_len > UINT32_MAX) { + return ndr_push_error( + ndr, + NDR_ERR_LENGTH, + "length overflow in ndr_push_u16string()"); + } + + if (ndr->flags & LIBNDR_ENCODING_FLAGS) { + return ndr_push_error( + ndr, + NDR_ERR_STRING, + "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS + " passed to ndr_push_u16string()\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + switch (ndr->flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_NULLTERM: + NDR_CHECK(ndr_push_bytes(ndr, s, s_len)); + break; + + default: + if (ndr->flags & LIBNDR_FLAG_REMAINING) { + NDR_CHECK(ndr_push_bytes(ndr, s, s_len)); + break; + } + + return ndr_push_error( + ndr, + NDR_ERR_STRING, + "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS + " passed to ndr_push_u16string()\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_u16string(struct ndr_print *ndr, + const char *name, + const unsigned char *s) +{ + return ndr_print_array_uint8(ndr, + name, + s, + utf16_len(s)); +} + +static uint32_t guess_string_array_size(struct ndr_pull *ndr, ndr_flags_type ndr_flags) +{ + /* + * Here we could do something clever like count the number of zeros in + * the ndr data, but it is probably sufficient to pick a lowish number + * (compared to the overhead of the talloc header) and let the + * exponential resizing deal with longer arrays. + */ + return 5; +} + +static enum ndr_err_code extend_string_array(struct ndr_pull *ndr, + const char ***_a, + uint32_t *count) +{ + const char **a = *_a; + uint32_t inc = *count / 4 + 3; + uint32_t alloc_size = *count + inc; + + if (alloc_size < *count) { + /* overflow ! */ + return NDR_ERR_ALLOC; + } + /* + * We allocate and zero two more bytes than we report back, so that + * the string array will always be NULL terminated. + */ + a = talloc_realloc(ndr->current_mem_ctx, a, + const char *, + alloc_size); + NDR_ERR_HAVE_NO_MEMORY(a); + + memset(a + *count, 0, inc * sizeof(a[0])); + *_a = a; + *count = alloc_size - 2; + return NDR_ERR_SUCCESS; +} + +/** + pull a general string array from the wire +*/ +_PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char ***_a) +{ + const char **a = NULL; + uint32_t count; + libndr_flags flags = ndr->flags; + libndr_flags saved_flags = ndr->flags; + uint32_t alloc_size; + + if (!(ndr_flags & NDR_SCALARS)) { + return NDR_ERR_SUCCESS; + } + + alloc_size = guess_string_array_size(ndr, ndr_flags); + a = talloc_zero_array(ndr->current_mem_ctx, const char *, alloc_size + 2); + NDR_ERR_HAVE_NO_MEMORY(a); + + switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) { + case LIBNDR_FLAG_STR_NULLTERM: + /* + * here the strings are null terminated + * but also the array is null terminated if LIBNDR_FLAG_REMAINING + * is specified + */ + for (count = 0;; count++) { + TALLOC_CTX *tmp_ctx; + const char *s = NULL; + if (count == alloc_size) { + NDR_CHECK(extend_string_array(ndr, + &a, + &alloc_size)); + } + + 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 ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING) + { + a[count] = s; + break; + } + 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%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + /* + * here the strings are not null terminated + * but separated by a null terminator + * + * which means the same as: + * Every string is null terminated except 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 + * + * The big difference with the case LIBNDR_FLAG_STR_NOTERM + + * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated + */ + 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; + if (count == alloc_size) { + NDR_CHECK(extend_string_array(ndr, + &a, + &alloc_size)); + } + + 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 = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1); + NDR_ERR_HAVE_NO_MEMORY(a); + *_a = a; + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\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, ndr_flags_type ndr_flags, const char **a) +{ + uint32_t count; + libndr_flags flags = ndr->flags; + libndr_flags 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])); + } + /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */ + if (!(flags & LIBNDR_FLAG_REMAINING)) + { + 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%"PRI_LIBNDR_FLAGS" (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%"PRI_LIBNDR_FLAGS"\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(%"PRIu32")", name, count); + ndr->depth++; + for (i=0;idepth--; +} + +_PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, libndr_flags flags) +{ + uint32_t i; + size_t size = 0; + int rawbytes = 0; + + if (flags & LIBNDR_FLAG_STR_RAW8) { + rawbytes = 1; + flags &= ~LIBNDR_FLAG_STR_RAW8; + } + + switch (flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_NULLTERM: + for (i = 0; i < count; i++) { + size += rawbytes?strlen(a[i]) + 1:strlen_m_term(a[i]); + } + break; + case LIBNDR_FLAG_STR_NOTERM: + for (i = 0; i < count; i++) { + size += rawbytes?strlen(a[i]):strlen_m(a[i]); + } + break; + default: + return 0; + } + + return size; +} + +/** + * 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; +} + +/** + * @brief Get the string length including the null terminator if available. + * + * This checks the string length based on the elements. The returned number + * includes the terminating null byte(s) if found. + * + * @param[in] _var The string to calculate the length for. + * + * @param[in] length The length of the buffer passed by _var. + * + * @param[in] element_size The element_size of a string char in bytes. + * + * @return The length of the strings or 0. + */ +static uint32_t ndr_string_n_length(const void *_var, + size_t length, + uint32_t element_size) +{ + size_t i = 0; + uint8_t zero[4] = {0,0,0,0}; + const char *var = (const char *)_var; + int cmp; + + if (element_size > 4) { + return 0; + } + + for (i = 0; i < length; i++, var += element_size) { + cmp = memcmp(var, zero, element_size); + if (cmp == 0) { + break; + } + } + + if (i == length) { + return length; + } + + 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; + uint32_t save_offset; + + if (count == 0) { + return NDR_ERR_RANGE; + } + + if (element_size && count - 1 > UINT32_MAX / element_size) { + return NDR_ERR_RANGE; + } + + save_offset = ndr->offset; + NDR_CHECK(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->offset = save_offset; + + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); + } + } + + ndr->offset = save_offset; + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, ndr_flags_type 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, ""); + if (*var == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "Failed to talloc_strdup() in ndr_pull_charset()"); + } + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr) && chset == CH_UTF16) { + chset = CH_UTF16BE; + } + + if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow"); + } + 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, + var, + &converted_size)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) +{ + size_t converted_size; + uint32_t str_len; + + if (length == 0) { + *var = talloc_strdup(ndr->current_mem_ctx, ""); + if (*var == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, + "Failed to talloc_strdup() in ndr_pull_charset_to_null()"); + } + return NDR_ERR_SUCCESS; + } + + if (NDR_BE(ndr) && chset == CH_UTF16) { + chset = CH_UTF16BE; + } + + if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow"); + } + NDR_PULL_NEED_BYTES(ndr, length*byte_mul); + + str_len = ndr_string_n_length(ndr->data+ndr->offset, length, byte_mul); + if (str_len == 0) { + return ndr_pull_error(ndr, NDR_ERR_LENGTH, + "Invalid length"); + } + + if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, + ndr->data+ndr->offset, str_len*byte_mul, + var, + &converted_size)) + { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character 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, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset) +{ + size_t required; + + if (NDR_BE(ndr) && chset == CH_UTF16) { + chset = CH_UTF16BE; + } + + if ((byte_mul != 0) && (length > SIZE_MAX/byte_mul)) { + return ndr_push_error(ndr, NDR_ERR_LENGTH, "length overflow"); + } + required = byte_mul * length; + + NDR_PUSH_NEED_BYTES(ndr, required); + + if (required) { + size_t size = 0; + + if (var == NULL) { + return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer"); + } + + if (!convert_string(CH_UNIX, chset, + var, strlen(var), + ndr->data+ndr->offset, required, &size)) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + + /* Make sure the remaining part of the string is filled with zeroes */ + if (size < required) { + memset(ndr->data+ndr->offset+size, 0, required-size); + } + } + + ndr->offset += required; + + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset) +{ + const char *str = var; + + if (str == NULL) { + str = "\0"; /* i.e. two zero bytes, for UTF16 null word. */ + length = 1; + } + + return ndr_push_charset(ndr, ndr_flags, str, length, byte_mul, chset); +} + +/* Return number of elements in a string in the specified charset */ +_PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset) +{ + switch (chset) { + /* case CH_UTF16: this has the same value as CH_UTF16LE */ + case CH_UTF16LE: + case CH_UTF16BE: + case CH_UTF16MUNGED: + case CH_UTF8: + return strlen_m_ext_term((const char *)var, CH_UNIX, chset); + case CH_DOS: + case CH_UNIX: + return strlen((const char *)var)+1; + default: + /* Fallback, this should never happen */ + return strlen((const char *)var)+1; + } +} diff --git a/librpc/ndr/ndr_svcctl.c b/librpc/ndr/ndr_svcctl.c new file mode 100644 index 0000000..83e581b --- /dev/null +++ b/librpc/ndr/ndr_svcctl.c @@ -0,0 +1,52 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special svcctl types + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_svcctl.h" + +_PUBLIC_ enum ndr_err_code ndr_push_ENUM_SERVICE_STATUSW_array(struct ndr_push *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r) +{ + uint32_t cntr_array_1; + + for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) { + NDR_CHECK(ndr_push_ENUM_SERVICE_STATUSW(ndr, NDR_SCALARS, &r[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) { + NDR_CHECK(ndr_push_ENUM_SERVICE_STATUSW(ndr, NDR_BUFFERS, &r[cntr_array_1])); + } + + return NDR_ERR_SUCCESS; + +} + +_PUBLIC_ enum ndr_err_code ndr_pull_ENUM_SERVICE_STATUSW_array(struct ndr_pull *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r) +{ + uint32_t cntr_array_1; + + for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) { + NDR_CHECK(ndr_pull_ENUM_SERVICE_STATUSW(ndr, NDR_SCALARS, &r[cntr_array_1])); + } + for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) { + NDR_CHECK(ndr_pull_ENUM_SERVICE_STATUSW(ndr, NDR_BUFFERS, &r[cntr_array_1])); + } + + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_svcctl.h b/librpc/ndr/ndr_svcctl.h new file mode 100644 index 0000000..e11ff69 --- /dev/null +++ b/librpc/ndr/ndr_svcctl.h @@ -0,0 +1,24 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling special svcctl types + + Copyright (C) Guenther Deschner 2009 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_push_ENUM_SERVICE_STATUSW_array(struct ndr_push *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r); +_PUBLIC_ enum ndr_err_code ndr_pull_ENUM_SERVICE_STATUSW_array(struct ndr_pull *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r); + diff --git a/librpc/ndr/ndr_table.c b/librpc/ndr/ndr_table.c new file mode 100644 index 0000000..69a3eda --- /dev/null +++ b/librpc/ndr/ndr_table.c @@ -0,0 +1,182 @@ +/* + Unix SMB/CIFS implementation. + + dcerpc utility functions + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Jelmer Vernooij 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 . +*/ + +#include "includes.h" +#include "../lib/util/dlinklist.h" +#include "librpc/ndr/libndr.h" +#include "librpc/ndr/ndr_table.h" +#undef strcasecmp + +static struct ndr_interface_list *ndr_interfaces; + +/* + register a ndr interface table +*/ +NTSTATUS ndr_table_register(const struct ndr_interface_table *table) +{ + struct ndr_interface_list *l; + + for (l = ndr_interfaces; l; l = l->next) { + /* + * If no GUID is supplied, use the name to determine + * uniqueness. + */ + if (GUID_all_zero(&table->syntax_id.uuid)) { + if (strcmp(table->name, + l->table->name) != 0) { + continue; + } + DBG_ERR("Attempt to register interface %s which has the " + "same name as already registered interface\n", + table->name); + } else { + if (!GUID_equal(&table->syntax_id.uuid, + &l->table->syntax_id.uuid)) { + continue; + } + DBG_ERR("Attempt to register interface %s which has the " + "same UUID as already registered interface %s\n", + table->name, l->table->name); + } + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + /* + * This is a singleton instance guaranteed + * by the above check to be only added once + * into the list so we can allocate off the NULL + * context. We never want this to be freed + * until process shutdown. If needed we could + * add a deregister function that walks and + * frees the list. + */ + + l = talloc(NULL, struct ndr_interface_list); + l->table = table; + + DLIST_ADD(ndr_interfaces, l); + + return NT_STATUS_OK; +} + +/* + find the pipe name for a local IDL interface +*/ +const char *ndr_interface_name(const struct GUID *uuid, uint32_t if_version) +{ + const struct ndr_interface_list *l; + for (l=ndr_table_list();l;l=l->next) { + if (GUID_equal(&l->table->syntax_id.uuid, uuid) && + l->table->syntax_id.if_version == if_version) { + return l->table->name; + } + } + return "UNKNOWN"; +} + +/* + find the number of calls defined by local IDL +*/ +int ndr_interface_num_calls(const struct GUID *uuid, uint32_t if_version) +{ + const struct ndr_interface_list *l; + for (l=ndr_table_list();l;l=l->next){ + if (GUID_equal(&l->table->syntax_id.uuid, uuid) && + l->table->syntax_id.if_version == if_version) { + return l->table->num_calls; + } + } + return -1; +} + + +/* + find a dcerpc interface by name +*/ +const struct ndr_interface_table *ndr_table_by_name(const char *name) +{ + const struct ndr_interface_list *l; + for (l=ndr_table_list();l;l=l->next) { + if (strcasecmp(l->table->name, name) == 0) { + return l->table; + } + } + return NULL; +} + +/* + find a dcerpc interface by syntax +*/ +const struct ndr_interface_table *ndr_table_by_syntax(const struct ndr_syntax_id *syntax) +{ + const struct ndr_interface_list *l; + if (GUID_all_zero(&syntax->uuid)) { + /* These are not unique */ + return NULL; + } + for (l=ndr_table_list();l;l=l->next) { + if (ndr_syntax_id_equal(&l->table->syntax_id, syntax)) { + return l->table; + } + } + return NULL; +} + +/* + find a dcerpc interface by uuid +*/ +const struct ndr_interface_table *ndr_table_by_uuid(const struct GUID *uuid) +{ + const struct ndr_interface_list *l; + if (GUID_all_zero(uuid)) { + /* These are not unique */ + return NULL; + } + for (l=ndr_table_list();l;l=l->next) { + if (GUID_equal(&l->table->syntax_id.uuid, uuid)) { + return l->table; + } + } + return NULL; +} + +/* + return the list of registered dcerpc_pipes +*/ +const struct ndr_interface_list *ndr_table_list(void) +{ + ndr_table_init(); + return ndr_interfaces; +} + + +NTSTATUS ndr_table_init(void) +{ + static bool initialized = false; + + if (initialized) return NT_STATUS_OK; + initialized = true; + + ndr_table_register_builtin_tables(); + + return NT_STATUS_OK; +} diff --git a/librpc/ndr/ndr_table.h b/librpc/ndr/ndr_table.h new file mode 100644 index 0000000..1f6858a --- /dev/null +++ b/librpc/ndr/ndr_table.h @@ -0,0 +1,37 @@ +/* + Unix SMB/CIFS implementation. + + dcerpc utility functions + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Jelmer Vernooij 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 . +*/ + +#ifndef _NDR_TABLE_PROTO_H_ +#define _NDR_TABLE_PROTO_H_ + +NTSTATUS ndr_table_register(const struct ndr_interface_table *table); +const char *ndr_interface_name(const struct GUID *uuid, uint32_t if_version); +int ndr_interface_num_calls(const struct GUID *uuid, uint32_t if_version); +const struct ndr_interface_table *ndr_table_by_name(const char *name); +const struct ndr_interface_table *ndr_table_by_syntax(const struct ndr_syntax_id *syntax); +const struct ndr_interface_table *ndr_table_by_uuid(const struct GUID *uuid); +const struct ndr_interface_list *ndr_table_list(void); +NTSTATUS ndr_table_init(void); +NTSTATUS ndr_table_register_builtin_tables(void); + +#endif /* _NDR_TABLE_PROTO_H_ */ + diff --git a/librpc/ndr/ndr_witness.c b/librpc/ndr/ndr_witness.c new file mode 100644 index 0000000..85ba62e --- /dev/null +++ b/librpc/ndr/ndr_witness.c @@ -0,0 +1,110 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling witness structures + + Copyright (C) Guenther Deschner 2015 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_witness.h" + +_PUBLIC_ enum ndr_err_code ndr_push_witness_notifyResponse(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct witness_notifyResponse *r) +{ + uint32_t cntr_messages_0; + { + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX); + NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_witness_notifyResponse_type(ndr, NDR_SCALARS, r->type)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_witness_notifyResponse(r, ndr->flags) - 20)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->messages)); + if (r->messages) { + libndr_flags _flags_save_witness_notifyResponse_message = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING); + { + struct ndr_push *_ndr_messages; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_messages, 4, ndr_size_witness_notifyResponse(r, ndr->flags) - 20)); + for (cntr_messages_0 = 0; cntr_messages_0 < (r->num); cntr_messages_0++) { + NDR_CHECK(ndr_push_set_switch_value(_ndr_messages, &r->messages[cntr_messages_0], r->type)); + NDR_CHECK(ndr_push_witness_notifyResponse_message(_ndr_messages, NDR_SCALARS, &r->messages[cntr_messages_0])); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_messages, 4, ndr_size_witness_notifyResponse(r, ndr->flags) - 20)); + } + ndr->flags = _flags_save_witness_notifyResponse_message; + } + NDR_CHECK(ndr_push_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_witness_notifyResponse(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct witness_notifyResponse *r) +{ + libndr_flags _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX); + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_witness_notifyResponse_type(ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num)); + { + libndr_flags _flags_save_witness_notifyResponse_message = ndr->flags; + uint32_t _ptr_messages; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_messages)); + if (_ptr_messages) { + NDR_PULL_ALLOC(ndr, r->messages); + } else { + r->messages = NULL; + } + if (r->messages) { + uint32_t size_messages_0 = 0; + uint32_t cntr_messages_0; + TALLOC_CTX *_mem_save_messages_0; + + size_messages_0 = r->num; + NDR_PULL_ALLOC_N(ndr, r->messages, size_messages_0); + _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0); + { + struct ndr_pull *_ndr_messages; + NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_messages, 4, r->length)); + for (cntr_messages_0 = 0; cntr_messages_0 < (size_messages_0); cntr_messages_0++) { + NDR_CHECK(ndr_pull_set_switch_value(_ndr_messages, &r->messages[cntr_messages_0], r->type)); + NDR_CHECK(ndr_pull_witness_notifyResponse_message(_ndr_messages, NDR_SCALARS, &r->messages[cntr_messages_0])); + } + NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_messages, 4, r->length)); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0); + } + ndr->flags = _flags_save_witness_notifyResponse_message; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + ndr->flags = _flags_save_STRUCT; + + return NDR_ERR_SUCCESS; +} diff --git a/librpc/ndr/ndr_witness.h b/librpc/ndr/ndr_witness.h new file mode 100644 index 0000000..1a129e6 --- /dev/null +++ b/librpc/ndr/ndr_witness.h @@ -0,0 +1,23 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling witness structures + + Copyright (C) Guenther Deschner 2015 + + 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 . +*/ + +_PUBLIC_ enum ndr_err_code ndr_push_witness_notifyResponse(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct witness_notifyResponse *r); +_PUBLIC_ enum ndr_err_code ndr_pull_witness_notifyResponse(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct witness_notifyResponse *r); diff --git a/librpc/ndr/ndr_wmi.h b/librpc/ndr/ndr_wmi.h new file mode 100644 index 0000000..7787bb1 --- /dev/null +++ b/librpc/ndr/ndr_wmi.h @@ -0,0 +1,24 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling DCOM string arrays + + Copyright (C) Jelmer Vernooij 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +enum ndr_err_code ndr_push_BSTR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct BSTR *r); +enum ndr_err_code ndr_pull_BSTR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct BSTR *r); diff --git a/librpc/ndr/ndr_xattr.c b/librpc/ndr/ndr_xattr.c new file mode 100644 index 0000000..0ffdce9 --- /dev/null +++ b/librpc/ndr/ndr_xattr.c @@ -0,0 +1,148 @@ +/* + Unix SMB/CIFS implementation. + + helper routines for XATTR marshalling + + Copyright (C) Stefan (metze) Metzmacher 2009 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_xattr.h" + +static char *ndr_compat_xattr_attrib_hex(TALLOC_CTX *mem_ctx, + const struct xattr_DOSATTRIB *r) +{ + char *attrib_hex = NULL; + + switch (r->version) { + case 0xFFFF: + attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32, + r->info.compatinfoFFFF.attrib); + break; + case 1: + attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32, + r->info.info1.attrib); + break; + case 2: + attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32, + r->info.oldinfo2.attrib); + break; + case 3: + if (!(r->info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) { + attrib_hex = talloc_strdup(mem_ctx, ""); + break; + } + attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32, + r->info.info3.attrib); + break; + default: + attrib_hex = talloc_strdup(mem_ctx, ""); + break; + } + + return attrib_hex; +} + +_PUBLIC_ enum ndr_err_code ndr_push_xattr_DOSATTRIB(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct xattr_DOSATTRIB *r) +{ + if (ndr_flags & NDR_SCALARS) { + char *attrib_hex = NULL; + + attrib_hex = ndr_compat_xattr_attrib_hex(ndr, r); + NDR_ERR_HAVE_NO_MEMORY(attrib_hex); + + NDR_CHECK(ndr_push_align(ndr, 4)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, attrib_hex)); + ndr->flags = _flags_save_string; + } + if (r->version == 0xFFFF) { + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version)); + NDR_CHECK(ndr_push_set_switch_value(ndr, &r->info, r->version)); + NDR_CHECK(ndr_push_xattr_DosInfo(ndr, NDR_SCALARS, &r->info)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ enum ndr_err_code ndr_pull_xattr_DOSATTRIB(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct xattr_DOSATTRIB *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + { + libndr_flags _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->attrib_hex)); + ndr->flags = _flags_save_string; + } + if (ndr->offset >= ndr->data_size) { + unsigned int dosattr; + int ret; + + if (r->attrib_hex[0] != '0') { + + } + if (r->attrib_hex[1] != 'x') { + + } + ret = sscanf(r->attrib_hex, "%x", &dosattr); + if (ret != 1) { + } + r->version = 0xFFFF; + r->info.compatinfoFFFF.attrib = dosattr; + return NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->version)); + if (r->version == 0xFFFF) { + return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, + "ndr_pull_xattr_DOSATTRIB: " + "invalid level 0x%02"PRIX16, + r->version); + } + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->info, r->version)); + NDR_CHECK(ndr_pull_xattr_DosInfo(ndr, NDR_SCALARS, &r->info)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +_PUBLIC_ void ndr_print_xattr_DOSATTRIB(struct ndr_print *ndr, const char *name, const struct xattr_DOSATTRIB *r) +{ + char *attrib_hex; + + ndr_print_struct(ndr, name, "xattr_DOSATTRIB"); + ndr->depth++; + + if (ndr->flags & LIBNDR_PRINT_SET_VALUES) { + attrib_hex = ndr_compat_xattr_attrib_hex(ndr, r); + } else { + attrib_hex = talloc_strdup(ndr, r->attrib_hex); + } + ndr_print_string(ndr, "attrib_hex", attrib_hex); + + ndr_print_uint16(ndr, "version", r->version); + ndr_print_set_switch_value(ndr, &r->info, r->version); + ndr_print_xattr_DosInfo(ndr, "info", &r->info); + ndr->depth--; +} diff --git a/librpc/ndr/ndr_xattr.h b/librpc/ndr/ndr_xattr.h new file mode 100644 index 0000000..893ac88 --- /dev/null +++ b/librpc/ndr/ndr_xattr.h @@ -0,0 +1,37 @@ +/* + Unix SMB/CIFS implementation. + + helper routines for XATTR marshalling + + Copyright (C) Stefan (metze) Metzmacher 2009 + + 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 . +*/ + +#ifndef _LIBRPC_NDR_NDR_XATTR_H +#define _LIBRPC_NDR_NDR_XATTR_H + +_PUBLIC_ enum ndr_err_code ndr_push_xattr_DOSATTRIB(struct ndr_push *ndr, + ndr_flags_type ndr_flags, + const struct xattr_DOSATTRIB *r); + +_PUBLIC_ enum ndr_err_code ndr_pull_xattr_DOSATTRIB(struct ndr_pull *ndr, + ndr_flags_type ndr_flags, + struct xattr_DOSATTRIB *r); + +_PUBLIC_ void ndr_print_xattr_DOSATTRIB(struct ndr_print *ndr, + const char *name, + const struct xattr_DOSATTRIB *r); + +#endif /* _LIBRPC_NDR_NDR_XATTR_H */ diff --git a/librpc/ndr/util.c b/librpc/ndr/util.c new file mode 100644 index 0000000..0eb7eba --- /dev/null +++ b/librpc/ndr/util.c @@ -0,0 +1,36 @@ +/* + 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 . +*/ + +#include "includes.h" +#include "../librpc/ndr/libndr.h" +#include "system/network.h" +#include "lib/util/util_net.h" + +_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)); +} + +_PUBLIC_ void ndr_zero_memory(void *ptr, size_t len) +{ + memset_s(ptr, len, 0, len); +} diff --git a/librpc/ndr/uuid.c b/librpc/ndr/uuid.c new file mode 100644 index 0000000..a759900 --- /dev/null +++ b/librpc/ndr/uuid.c @@ -0,0 +1,258 @@ +/* + 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 . +*/ + +#include "replace.h" +#include "lib/util/samba_util.h" +#include "lib/util/genrand.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "lib/util/util_str_hex.h" + +_PUBLIC_ NTSTATUS GUID_to_ndr_buf( + const struct GUID *guid, struct GUID_ndr_buf *buf) +{ + DATA_BLOB b = { .data = buf->buf, .length = sizeof(buf->buf), }; + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_into_fixed_blob( + &b, guid, (ndr_push_flags_fn_t)ndr_push_GUID); + return ndr_map_error2ntstatus(ndr_err); +} + +/** + build a NDR blob from a GUID +*/ +_PUBLIC_ NTSTATUS GUID_to_ndr_blob(const struct GUID *guid, TALLOC_CTX *mem_ctx, DATA_BLOB *b) +{ + struct GUID_ndr_buf buf = { .buf = {0}, }; + NTSTATUS status; + + status = GUID_to_ndr_buf(guid, &buf); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *b = data_blob_talloc(mem_ctx, buf.buf, sizeof(buf.buf)); + if (b->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} + + +/** + build a GUID from a NDR data blob +*/ +_PUBLIC_ NTSTATUS GUID_from_ndr_blob(const DATA_BLOB *b, struct GUID *guid) +{ + enum ndr_err_code ndr_err = + ndr_pull_struct_blob_all_noalloc(b, guid, + (ndr_pull_flags_fn_t)ndr_pull_GUID); + return ndr_map_error2ntstatus(ndr_err); +} + + +/** + build a GUID from a string +*/ +_PUBLIC_ NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid) +{ + bool ok; + + if (s->data == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (s->length == 36) { + ok = parse_guid_string((char *)s->data, guid); + return ok ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER; + } + + if (s->length == 38) { + if (s->data[0] != '{' || s->data[37] != '}') { + return NT_STATUS_INVALID_PARAMETER; + } + ok = parse_guid_string((char *)s->data + 1, guid); + return ok ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER; + } + + if (s->length == 32) { + uint8_t buf16[16] = {0}; + DATA_BLOB blob16 = { .data = buf16, .length = sizeof(buf16) }; + size_t rlen = strhex_to_str((char *)blob16.data, blob16.length, + (const char *)s->data, s->length); + if (rlen != blob16.length) { + return NT_STATUS_INVALID_PARAMETER; + } + + return GUID_from_ndr_blob(&blob16, guid); + } + + if (s->length == 16) { + return GUID_from_ndr_blob(s, guid); + } + + return NT_STATUS_INVALID_PARAMETER; +} + +/** + build a GUID from a string +*/ +_PUBLIC_ NTSTATUS GUID_from_string(const char *s, struct GUID *guid) +{ + DATA_BLOB blob = data_blob_string_const(s); + return GUID_from_data_blob(&blob, guid); +} + +/** + * generate a random GUID + */ +_PUBLIC_ 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) +{ + return (struct GUID) { .time_low = 0 }; +} + +_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) +{ + return (GUID_compare(u1, u2) == 0); +} + +_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 ? 1 : -1; + } + + if (u1->time_mid != u2->time_mid) { + return u1->time_mid > u2->time_mid ? 1 : -1; + } + + if (u1->time_hi_and_version != u2->time_hi_and_version) { + return u1->time_hi_and_version > u2->time_hi_and_version ? 1 : -1; + } + + if (u1->clock_seq[0] != u2->clock_seq[0]) { + return u1->clock_seq[0] > u2->clock_seq[0] ? 1 : -1; + } + + if (u1->clock_seq[1] != u2->clock_seq[1]) { + return u1->clock_seq[1] > u2->clock_seq[1] ? 1 : -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) +{ + struct GUID_txt_buf buf; + return talloc_strdup(mem_ctx, GUID_buf_string(guid, &buf)); +} + +/** + * Does the same without allocating memory, using the structure buffer. + * Useful for debug messages, so that you do not have to talloc_free the result + */ +_PUBLIC_ char* GUID_buf_string(const struct GUID *guid, + struct GUID_txt_buf *dst) +{ + if (!guid) { + return NULL; + } + snprintf(dst->buf, sizeof(dst->buf), + "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8, + 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]); + return dst->buf; +} + +_PUBLIC_ char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + struct GUID_txt_buf buf; + char *ret = talloc_asprintf( + mem_ctx, "{%s}", GUID_buf_string(guid, &buf)); + return ret; +} + +_PUBLIC_ char *GUID_hexstring(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + char *ret = NULL; + DATA_BLOB guid_blob = { .data = NULL }; + NTSTATUS status; + + status = GUID_to_ndr_blob(guid, mem_ctx, &guid_blob); + if (NT_STATUS_IS_OK(status)) { + ret = data_blob_hex_string_upper(mem_ctx, &guid_blob); + } + TALLOC_FREE(guid_blob.data); + return ret; +} + +_PUBLIC_ bool ndr_policy_handle_empty(const struct policy_handle *h) +{ + return (h->handle_type == 0 && GUID_all_zero(&h->uuid)); +} + +_PUBLIC_ bool ndr_policy_handle_equal(const struct policy_handle *hnd1, + const struct policy_handle *hnd2) +{ + if (!hnd1 || !hnd2) { + return false; + } + + return (memcmp(hnd1, hnd2, sizeof(*hnd1)) == 0); +} -- cgit v1.2.3