From fbdcf2663b56007a438ac4f0d8d82436b1bfe688 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 11 Jul 2006 18:01:26 +0000 Subject: r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need to do the upper layer directories but this is what everyone is waiting for.... Jeremy. (This used to be commit 9dafb7f48ca3e7af956b0a7d1720c2546fc4cfb8) --- source3/libndr/libndr.h | 296 +++++++++++++ source3/libndr/misc.h | 37 ++ source3/libndr/ndr.c | 961 ++++++++++++++++++++++++++++++++++++++++ source3/libndr/ndr_basic.c | 826 ++++++++++++++++++++++++++++++++++ source3/libndr/ndr_misc.c | 171 +++++++ source3/libndr/ndr_sec.h | 35 ++ source3/libndr/ndr_sec_helper.c | 187 ++++++++ source3/libndr/ndr_string.c | 612 +++++++++++++++++++++++++ source3/libndr/security.h | 260 +++++++++++ source3/libndr/sid.c | 97 ++++ 10 files changed, 3482 insertions(+) create mode 100644 source3/libndr/libndr.h create mode 100644 source3/libndr/misc.h create mode 100644 source3/libndr/ndr.c create mode 100644 source3/libndr/ndr_basic.c create mode 100644 source3/libndr/ndr_misc.c create mode 100644 source3/libndr/ndr_sec.h create mode 100644 source3/libndr/ndr_sec_helper.c create mode 100644 source3/libndr/ndr_string.c create mode 100644 source3/libndr/security.h create mode 100644 source3/libndr/sid.c (limited to 'source3/libndr') diff --git a/source3/libndr/libndr.h b/source3/libndr/libndr.h new file mode 100644 index 0000000000..817c461075 --- /dev/null +++ b/source3/libndr/libndr.h @@ -0,0 +1,296 @@ +/* + 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 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. +*/ + +#ifndef __LIBNDR_H__ +#define __LIBNDR_H__ + +#define _PRINTF_ATTRIBUTE(a,b) + +#include "libndr/misc.h" +#include "libndr/security.h" + +struct dcerpc_syntax_id { + struct GUID uuid; + uint32_t if_version; +}/* [public] */; + +/* + this provides definitions for the libcli/rpc/ MSRPC library +*/ + + +/* + this is used by the token store/retrieve code +*/ +struct ndr_token_list { + struct ndr_token_list *next, *prev; + const void *key; + uint32_t value; +}; + +/* this is the base structure passed to routines that + parse MSRPC formatted data + + note that in Samba4 we use separate routines and structures for + MSRPC marshalling and unmarshalling. Also note that these routines + are being kept deliberately very simple, and are not tied to a + particular transport +*/ +struct ndr_pull { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t data_size; + uint32_t offset; + + uint32_t relative_base_offset; + struct ndr_token_list *relative_base_list; + + struct ndr_token_list *relative_list; + struct ndr_token_list *array_size_list; + struct ndr_token_list *array_length_list; + struct ndr_token_list *switch_list; + + TALLOC_CTX *current_mem_ctx; + + /* this is used to ensure we generate unique reference IDs + between request and reply */ + uint32_t ptr_count; +}; + +struct ndr_pull_save { + uint32_t data_size; + uint32_t offset; + struct ndr_pull_save *next; +}; + +/* structure passed to functions that generate NDR formatted data */ +struct ndr_push { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint8_t *data; + uint32_t alloc_size; + uint32_t offset; + + uint32_t relative_base_offset; + struct ndr_token_list *relative_base_list; + + struct ndr_token_list *switch_list; + struct ndr_token_list *relative_list; + struct ndr_token_list *nbt_string_list; + + /* this is used to ensure we generate unique reference IDs */ + uint32_t ptr_count; +}; + +struct ndr_push_save { + uint32_t offset; + struct ndr_push_save *next; +}; + + +/* structure passed to functions that print IDL structures */ +struct ndr_print { + uint32_t flags; /* LIBNDR_FLAG_* */ + uint32_t depth; + struct ndr_token_list *switch_list; + void (*print)(struct ndr_print *, const char *, ...); + void *private_data; +}; + +#define LIBNDR_FLAG_BIGENDIAN (1<<0) +#define LIBNDR_FLAG_NOALIGN (1<<1) + +#define LIBNDR_FLAG_STR_ASCII (1<<2) +#define LIBNDR_FLAG_STR_LEN4 (1<<3) +#define LIBNDR_FLAG_STR_SIZE4 (1<<4) +#define LIBNDR_FLAG_STR_NOTERM (1<<5) +#define LIBNDR_FLAG_STR_NULLTERM (1<<6) +#define LIBNDR_FLAG_STR_SIZE2 (1<<7) +#define LIBNDR_FLAG_STR_BYTESIZE (1<<8) +#define LIBNDR_FLAG_STR_FIXLEN32 (1<<9) +#define LIBNDR_FLAG_STR_CONFORMANT (1<<10) +#define LIBNDR_FLAG_STR_CHARLEN (1<<11) +#define LIBNDR_FLAG_STR_UTF8 (1<<12) +#define LIBNDR_FLAG_STR_FIXLEN15 (1<<13) +#define LIBNDR_STRING_FLAGS (0x7FFC) + + +#define LIBNDR_FLAG_REF_ALLOC (1<<20) +#define LIBNDR_FLAG_REMAINING (1<<21) +#define LIBNDR_FLAG_ALIGN2 (1<<22) +#define LIBNDR_FLAG_ALIGN4 (1<<23) +#define LIBNDR_FLAG_ALIGN8 (1<<24) + +#define LIBNDR_ALIGN_FLAGS (LIBNDR_FLAG_ALIGN2|LIBNDR_FLAG_ALIGN4|LIBNDR_FLAG_ALIGN8) + +#define LIBNDR_PRINT_ARRAY_HEX (1<<25) +#define LIBNDR_PRINT_SET_VALUES (1<<26) + +/* used to force a section of IDL to be little-endian */ +#define LIBNDR_FLAG_LITTLE_ENDIAN (1<<27) + +/* used to check if alignment padding is zero */ +#define LIBNDR_FLAG_PAD_CHECK (1<<28) + +/* set if an object uuid will be present */ +#define LIBNDR_FLAG_OBJECT_PRESENT (1<<30) + +/* set to avoid recursion in ndr_size_*() calculation */ +#define LIBNDR_FLAG_NO_NDR_SIZE (1<<31) + +/* useful macro for debugging */ +#define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p) +#define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_fn_t)ndr_print_ ##type, #p, level, p) +#define NDR_PRINT_FUNCTION_DEBUG(type, flags, p) ndr_print_function_debug((ndr_print_function_t)ndr_print_ ##type, #type, flags, p) +#define NDR_PRINT_BOTH_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_BOTH, p) +#define NDR_PRINT_OUT_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_OUT, p) +#define NDR_PRINT_IN_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_IN | NDR_SET_VALUES, p) + +#define NDR_BE(ndr) (((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN) + +enum ndr_err_code { + 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 +}; + +enum ndr_compression_alg { + NDR_COMPRESSION_MSZIP = 2, + NDR_COMPRESSION_XPRESS = 3 +}; + +/* + flags passed to control parse flow +*/ +#define NDR_SCALARS 1 +#define NDR_BUFFERS 2 + +/* + flags passed to ndr_print_*() +*/ +#define NDR_IN 1 +#define NDR_OUT 2 +#define NDR_BOTH 3 +#define NDR_SET_VALUES 4 + +#define NDR_PULL_NEED_BYTES(ndr, n) do { \ + if ((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size) { \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %u", (unsigned)n); \ + } \ +} while(0) + +#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n) + +#define NDR_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1)) + +#define NDR_PULL_ALIGN(ndr, n) do { \ + if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ + if (ndr->flags & LIBNDR_FLAG_PAD_CHECK) { \ + ndr_check_padding(ndr, n); \ + } \ + ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ + } \ + if (ndr->offset > ndr->data_size) { \ + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %u", (unsigned)n); \ + } \ +} while(0) + +#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, ndr->offset+(n))) + +#define NDR_PUSH_ALIGN(ndr, n) do { \ + if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ + uint32_t _pad = ((ndr->offset + (n-1)) & ~(n-1)) - ndr->offset; \ + while (_pad--) NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0)); \ + } \ +} while(0) + +/* these are used to make the error checking on each element in libndr + less tedious, hopefully making the code more readable */ +#define NDR_CHECK(call) do { NTSTATUS _status; \ + _status = call; \ + if (!NT_STATUS_IS_OK(_status)) \ + return _status; \ + } while (0) + +#define NDR_PULL_GET_MEM_CTX(ndr) (ndr->current_mem_ctx) + +#define NDR_PULL_SET_MEM_CTX(ndr, mem_ctx, flgs) do {\ + if ( !(flgs) || (ndr->flags & flgs) ) {\ + if (!(mem_ctx)) {\ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "NDR_PULL_SET_MEM_CTX(NULL): %s\n", __location__); \ + }\ + ndr->current_mem_ctx = 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_SIZE(ndr, s, size) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_size(ndr->current_mem_ctx, size); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u failed: %s\n",(unsigned)size, __location__); \ +} while (0) + +#define NDR_PULL_ALLOC(ndr, s) NDR_PULL_ALLOC_SIZE(ndr, s, sizeof(*(s))) + +#define NDR_PULL_ALLOC_N_SIZE(ndr, s, n, elsize) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_array_size(ndr->current_mem_ctx, elsize, n); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u * %u failed: %s\n", (unsigned)n, (unsigned)elsize, __location__); \ +} while (0) + +#define NDR_PULL_ALLOC_N(ndr, s, n) NDR_PULL_ALLOC_N_SIZE(ndr, s, n, sizeof(*(s))) + + +#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \ + (s) = talloc_size(ndr, size); \ + if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %u failed: %s\n", (unsigned)size, __location__); \ +} while (0) + +#define NDR_PUSH_ALLOC(ndr, s) NDR_PUSH_ALLOC_SIZE(ndr, s, sizeof(*(s))) + +/* these are used when generic fn pointers are needed for ndr push/pull fns */ +typedef NTSTATUS (*ndr_push_flags_fn_t)(struct ndr_push *, int ndr_flags, const void *); +typedef NTSTATUS (*ndr_pull_flags_fn_t)(struct ndr_pull *, int ndr_flags, void *); +typedef void (*ndr_print_fn_t)(struct ndr_print *, const char *, const void *); +typedef void (*ndr_print_function_t)(struct ndr_print *, const char *, int, const void *); + +extern const struct dcerpc_syntax_id ndr_transfer_syntax; +extern const struct dcerpc_syntax_id ndr64_transfer_syntax; + +#endif /* __LIBNDR_H__ */ diff --git a/source3/libndr/misc.h b/source3/libndr/misc.h new file mode 100644 index 0000000000..d929379870 --- /dev/null +++ b/source3/libndr/misc.h @@ -0,0 +1,37 @@ +/* header auto-generated by pidl */ + +#ifndef _HEADER_misc +#define _HEADER_misc + +struct GUID { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq[2]; + uint8_t node[6]; +}/* [noprint,gensize,public,noejs] */; + +struct policy_handle { + uint32_t handle_type; + struct GUID uuid; +}/* [public] */; + +enum netr_SchannelType { + SEC_CHAN_WKSTA=2, + SEC_CHAN_DOMAIN=4, + SEC_CHAN_BDC=6 +}; + +enum netr_SamDatabaseID { + SAM_DATABASE_DOMAIN=0, + SAM_DATABASE_BUILTIN=1, + SAM_DATABASE_PRIVS=2 +}; + +enum samr_RejectReason { + SAMR_REJECT_OTHER=0, + SAMR_REJECT_TOO_SHORT=1, + SAMR_REJECT_COMPLEXITY=2 +}; + +#endif /* _HEADER_misc */ diff --git a/source3/libndr/ndr.c b/source3/libndr/ndr.c new file mode 100644 index 0000000000..2aff7a88f0 --- /dev/null +++ b/source3/libndr/ndr.c @@ -0,0 +1,961 @@ +/* + 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 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. +*/ + +/* + this provides the core routines for NDR parsing functions + + see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details + of NDR encoding rules +*/ + +#include "includes.h" + +#define NDR_BASE_MARSHALL_SIZE 1024 + +/* this guid indicates NDR encoding in a protocol tower */ +const struct dcerpc_syntax_id ndr_transfer_syntax = { + { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} }, + 2 +}; + +const struct dcerpc_syntax_id ndr64_transfer_syntax = { + { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} }, + 1 +}; + +/* + work out the number of bytes needed to align on a n byte boundary +*/ +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 +*/ +struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx) +{ + struct ndr_pull *ndr; + + ndr = talloc_zero(mem_ctx, struct ndr_pull); + if (!ndr) return NULL; + ndr->current_mem_ctx = mem_ctx; + + ndr->data = blob->data; + ndr->data_size = blob->length; + + return ndr; +} + +/* + advance by 'size' bytes +*/ +NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32_t size) +{ + ndr->offset += size; + if (ndr->offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_advance by %u failed", + size); + } + return NT_STATUS_OK; +} + +/* + set the parse offset to 'ofs' +*/ +static NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs) +{ + ndr->offset = ofs; + if (ndr->offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_set_offset %u failed", + ofs); + } + return NT_STATUS_OK; +} + +/* save the offset/size of the current ndr state */ +void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save) +{ + save->offset = ndr->offset; + save->data_size = ndr->data_size; +} + +/* restore the size/offset of a ndr structure */ +void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save) +{ + ndr->offset = save->offset; + ndr->data_size = save->data_size; +} + + +/* create a ndr_push structure, ready for some marshalling */ +struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx) +{ + struct ndr_push *ndr; + + ndr = talloc_zero(mem_ctx, struct ndr_push); + if (!ndr) { + return NULL; + } + + ndr->flags = 0; + ndr->alloc_size = NDR_BASE_MARSHALL_SIZE; + ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size); + if (!ndr->data) { + return NULL; + } + + return ndr; +} + + +/* create a ndr_push structure, ready for some marshalling */ +struct ndr_push *ndr_push_init(void) +{ + return ndr_push_init_ctx(NULL); +} + +/* free a ndr_push structure */ +void ndr_push_free(struct ndr_push *ndr) +{ + talloc_free(ndr); +} + + +/* return a DATA_BLOB structure for the current ndr_push marshalled data */ +DATA_BLOB ndr_push_blob(struct ndr_push *ndr) +{ + DATA_BLOB blob; + blob.data = ndr->data; + blob.length = ndr->offset; + blob.free = NULL; + if (ndr->alloc_size > ndr->offset) { + ndr->data[ndr->offset] = 0; + } + return blob; +} + + +/* + expand the available space in the buffer to 'size' +*/ +NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size) +{ + if (ndr->alloc_size > size) { + return NT_STATUS_OK; + } + + ndr->alloc_size += NDR_BASE_MARSHALL_SIZE; + if (size+1 > ndr->alloc_size) { + ndr->alloc_size = size+1; + } + ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size); + if (!ndr->data) { + return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u", + ndr->alloc_size); + } + + return NT_STATUS_OK; +} + +void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3) +{ + va_list ap; + char *s = NULL; + int i; + + va_start(ap, format); + vasprintf(&s, format, ap); + va_end(ap); + + for (i=0;idepth;i++) { + DEBUG(0,(" ")); + } + + DEBUG(0,("%s\n", s)); + free(s); +} + +static void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3) +{ + va_list ap; + int i; + + for (i=0;idepth;i++) { + ndr->private_data = talloc_asprintf_append(ndr->private_data, " "); + } + + va_start(ap, format); + ndr->private_data = talloc_vasprintf_append(ndr->private_data, format, ap); + va_end(ap); + ndr->private_data = talloc_asprintf_append(ndr->private_data, "\n"); +} + +/* + a useful helper function for printing idl structures via DEBUG() +*/ +void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl unions via DEBUG() +*/ +void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + ndr_print_set_switch_value(ndr, ptr, level); + fn(ndr, name, ptr); + talloc_free(ndr); +} + +/* + a useful helper function for printing idl function calls via DEBUG() +*/ +void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr) +{ + struct ndr_print *ndr; + + ndr = talloc_zero(NULL, struct ndr_print); + if (!ndr) return; + ndr->print = ndr_print_debug_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, flags, ptr); + talloc_free(ndr); +} + + +/* + a useful helper function for printing idl function calls to a string +*/ +char *ndr_print_function_string(TALLOC_CTX *mem_ctx, + ndr_print_function_t fn, const char *name, + int flags, void *ptr) +{ + struct ndr_print *ndr; + char *ret = NULL; + + ndr = talloc_zero(mem_ctx, struct ndr_print); + if (!ndr) return NULL; + if (!(ndr->private_data = talloc_strdup(mem_ctx, ""))) { + TALLOC_FREE(ndr); + return NULL; + } + ndr->print = ndr_print_string_helper; + ndr->depth = 1; + ndr->flags = 0; + fn(ndr, name, flags, ptr); + ret = ndr->private_data; + talloc_free(ndr); + return ret; +} + +void ndr_set_flags(uint32_t *pflags, uint32_t new_flags) +{ + /* the big/little endian flags are inter-dependent */ + if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) { + (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN; + } + if (new_flags & LIBNDR_FLAG_BIGENDIAN) { + (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN; + } + if (new_flags & LIBNDR_FLAG_REMAINING) { + (*pflags) &= ~LIBNDR_ALIGN_FLAGS; + } + if (new_flags & LIBNDR_ALIGN_FLAGS) { + (*pflags) &= ~LIBNDR_FLAG_REMAINING; + } + (*pflags) |= new_flags; +} + +static NTSTATUS ndr_map_error(enum ndr_err_code ndr_err) +{ + switch (ndr_err) { + 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; + default: + break; + } + + /* we should map all error codes to different status codes */ + return NT_STATUS_INVALID_PARAMETER; +} + +/* + return and possibly log an NDR error +*/ +NTSTATUS ndr_pull_error(struct ndr_pull *ndr, + enum ndr_err_code ndr_err, + const char *format, ...) _PRINTF_ATTRIBUTE(3,4) +{ + char *s=NULL; + va_list ap; + + va_start(ap, format); + vasprintf(&s, format, ap); + va_end(ap); + + DEBUG(3,("ndr_pull_error(%u): %s\n", ndr_err, s)); + + free(s); + + return ndr_map_error(ndr_err); +} + +/* + return and possibly log an NDR error +*/ +NTSTATUS ndr_push_error(struct ndr_push *ndr, + enum ndr_err_code ndr_err, + const char *format, ...) _PRINTF_ATTRIBUTE(3,4) +{ + char *s=NULL; + va_list ap; + + va_start(ap, format); + vasprintf(&s, format, ap); + va_end(ap); + + DEBUG(3,("ndr_push_error(%u): %s\n", ndr_err, s)); + + free(s); + + return ndr_map_error(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 +*/ +NTSTATUS ndr_pull_subcontext_start(struct ndr_pull *ndr, + struct ndr_pull **_subndr, + size_t header_size, + ssize_t size_is) +{ + struct ndr_pull *subndr; + uint32_t r_content_size; + + switch (header_size) { + case 0: { + uint32_t content_size = ndr->data_size - ndr->offset; + if (size_is >= 0) { + content_size = size_is; + } + r_content_size = content_size; + break; + } + + case 2: { + uint16_t content_size; + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size)); + if (size_is >= 0 && size_is != content_size) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", + (int)size_is, (int)content_size); + } + r_content_size = content_size; + break; + } + + case 4: { + uint32_t content_size; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size)); + if (size_is >= 0 && size_is != content_size) { + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", + (int)size_is, (int)content_size); + } + r_content_size = content_size; + break; + } + default: + return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", + (int)header_size); + } + + NDR_PULL_NEED_BYTES(ndr, r_content_size); + + subndr = talloc_zero(ndr, struct ndr_pull); + NT_STATUS_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags; + subndr->current_mem_ctx = ndr->current_mem_ctx; + + subndr->data = ndr->data + ndr->offset; + subndr->offset = 0; + subndr->data_size = r_content_size; + + *_subndr = subndr; + return NT_STATUS_OK; +} + +NTSTATUS ndr_pull_subcontext_end(struct ndr_pull *ndr, + struct ndr_pull *subndr, + size_t header_size, + ssize_t size_is) +{ + uint32_t advance; + if (size_is >= 0) { + advance = size_is; + } else if (header_size > 0) { + advance = subndr->data_size; + } else { + advance = subndr->offset; + } + NDR_CHECK(ndr_pull_advance(ndr, advance)); + return NT_STATUS_OK; +} + +NTSTATUS 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); + NT_STATUS_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags; + + *_subndr = subndr; + return NT_STATUS_OK; +} + +/* + push a subcontext header +*/ +NTSTATUS ndr_push_subcontext_end(struct ndr_push *ndr, + struct ndr_push *subndr, + size_t header_size, + ssize_t size_is) +{ + if (size_is >= 0) { + ssize_t padding_len = size_is - subndr->offset; + if (padding_len > 0) { + NDR_CHECK(ndr_push_zero(subndr, padding_len)); + } else if (padding_len < 0) { + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)", + (int)subndr->offset, (int)size_is); + } + } + + switch (header_size) { + case 0: + break; + + case 2: + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset)); + break; + + case 4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset)); + break; + + default: + return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d", + (int)header_size); + } + + NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset)); + return NT_STATUS_OK; +} + +/* + store a token in the ndr context, for later retrieval +*/ +NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx, + struct ndr_token_list **list, + const void *key, + uint32_t value) +{ + struct ndr_token_list *tok; + tok = talloc(mem_ctx, struct ndr_token_list); + if (tok == NULL) { + return NT_STATUS_NO_MEMORY; + } + tok->key = key; + tok->value = value; + DLIST_ADD((*list), tok); + return NT_STATUS_OK; +} + +/* + retrieve a token from a ndr context, using cmp_fn to match the tokens +*/ +NTSTATUS ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v, + comparison_fn_t _cmp_fn, BOOL _remove_tok) +{ + struct ndr_token_list *tok; + for (tok=*list;tok;tok=tok->next) { + if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found; + else if (!_cmp_fn && tok->key == key) goto found; + } + return ndr_map_error(NDR_ERR_TOKEN); +found: + *v = tok->value; + if (_remove_tok) { + DLIST_REMOVE((*list), tok); + talloc_free(tok); + } + return NT_STATUS_OK; +} + +/* + retrieve a token from a ndr context +*/ +NTSTATUS 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 +*/ +uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key) +{ + NTSTATUS status; + uint32_t v; + status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, False); + if (NT_STATUS_IS_OK(status)) return v; + return 0; +} + +/* + pull an array size field and add it to the array_size_list token list +*/ +NTSTATUS ndr_pull_array_size(struct ndr_pull *ndr, const void *p) +{ + uint32_t size; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size)); + return ndr_token_store(ndr, &ndr->array_size_list, p, size); +} + +/* + get the stored array size field +*/ +uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->array_size_list, p); +} + +/* + check the stored array size field +*/ +NTSTATUS ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size) +{ + uint32_t stored; + stored = ndr_token_peek(&ndr->array_size_list, p); + if (stored != size) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array size - got %u expected %u\n", + stored, size); + } + return NT_STATUS_OK; +} + +/* + pull an array length field and add it to the array_length_list token list +*/ +NTSTATUS ndr_pull_array_length(struct ndr_pull *ndr, const void *p) +{ + uint32_t length, offset; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &offset)); + if (offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "non-zero array offset %u\n", offset); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length)); + return ndr_token_store(ndr, &ndr->array_length_list, p, length); +} + +/* + get the stored array length field +*/ +uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->array_length_list, p); +} + +/* + check the stored array length field +*/ +NTSTATUS ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length) +{ + uint32_t stored; + stored = ndr_token_peek(&ndr->array_length_list, p); + if (stored != length) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array length - got %u expected %u\n", + stored, length); + } + return NT_STATUS_OK; +} + +/* + store a switch value + */ +NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val) +{ + return ndr_token_store(ndr, &ndr->switch_list, p, val); +} + +NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val) +{ + return ndr_token_store(ndr, &ndr->switch_list, p, val); +} + +NTSTATUS 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 + */ +uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p) +{ + return ndr_token_peek(&ndr->switch_list, p); +} + +/* + pull a struct from a blob using NDR +*/ +NTSTATUS 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); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p); +} + +/* + pull a struct from a blob using NDR - failing if all bytes are not consumed +*/ +NTSTATUS 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; + NTSTATUS status; + + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) return status; + if (ndr->offset != ndr->data_size) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + return status; +} + +/* + pull a union from a blob using NDR, given the union discriminator +*/ +NTSTATUS 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; + NTSTATUS status; + + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + ndr_pull_set_switch_value(ndr, p, level); + status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) return status; + if (ndr->offset != ndr->data_size) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + return status; +} + +/* + push a struct to a blob using NDR +*/ +NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, + ndr_push_flags_fn_t fn) +{ + NTSTATUS status; + struct ndr_push *ndr; + ndr = ndr_push_init_ctx(mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *blob = ndr_push_blob(ndr); + + return NT_STATUS_OK; +} + +/* + push a union to a blob using NDR +*/ +NTSTATUS ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, + uint32_t level, ndr_push_flags_fn_t fn) +{ + NTSTATUS status; + struct ndr_push *ndr; + ndr = ndr_push_init_ctx(mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + ndr_push_set_switch_value(ndr, p, level); + status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *blob = ndr_push_blob(ndr); + + return NT_STATUS_OK; +} + +/* + generic ndr_size_*() handler for structures +*/ +size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push) +{ + struct ndr_push *ndr; + NTSTATUS status; + size_t ret; + + /* avoid recursion */ + if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0; + + ndr = ndr_push_init_ctx(NULL); + if (!ndr) return 0; + ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE; + status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) { + return 0; + } + ret = ndr->offset; + talloc_free(ndr); + return ret; +} + +/* + generic ndr_size_*() handler for unions +*/ +size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push) +{ + struct ndr_push *ndr; + NTSTATUS status; + size_t ret; + + /* avoid recursion */ + if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0; + + ndr = ndr_push_init_ctx(NULL); + if (!ndr) return 0; + ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE; + ndr_push_set_switch_value(ndr, p, level); + status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p); + if (!NT_STATUS_IS_OK(status)) { + return 0; + } + ret = ndr->offset; + talloc_free(ndr); + return ret; +} + +/* + get the current base for relative pointers for the push +*/ +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 +*/ +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 +*/ +NTSTATUS ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset) +{ + ndr->relative_base_offset = offset; + return ndr_token_store(ndr, &ndr->relative_base_list, p, offset); +} + +/* + setup the current base for relative pointers for the push + called in the NDR_BUFFERS stage +*/ +NTSTATUS 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 +*/ +NTSTATUS ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p) +{ + if (p == NULL) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + return NT_STATUS_OK; + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset)); + return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF); +} + +/* + push a relative object - stage2 + this is called during buffers processing +*/ +NTSTATUS ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p) +{ + struct ndr_push_save save; + uint32_t ptr_offset = 0xFFFFFFFF; + if (p == NULL) { + return NT_STATUS_OK; + } + ndr_push_save(ndr, &save); + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset)); + if (ptr_offset > ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)", + ptr_offset, ndr->offset); + } + ndr->offset = ptr_offset; + if (save.offset < ndr->relative_base_offset) { + return ndr_push_error(ndr, NDR_ERR_BUFSIZE, + "ndr_push_relative_ptr2 save.offset(%u) < ndr->relative_base_offset(%u)", + save.offset, ndr->relative_base_offset); + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset - ndr->relative_base_offset)); + ndr_push_restore(ndr, &save); + return NT_STATUS_OK; +} + +/* + get the current base for relative pointers for the pull +*/ +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 +*/ +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 +*/ +NTSTATUS ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset) +{ + ndr->relative_base_offset = offset; + return ndr_token_store(ndr, &ndr->relative_base_list, p, offset); +} + +/* + setup the current base for relative pointers for the pull + called in the NDR_BUFFERS stage +*/ +NTSTATUS 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 +*/ +NTSTATUS ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset) +{ + rel_offset += ndr->relative_base_offset; + if (rel_offset > ndr->data_size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)", + rel_offset, ndr->data_size); + } + return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset); +} + +/* + pull a relative object - stage2 + called during BUFFERS processing +*/ +NTSTATUS ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p) +{ + uint32_t rel_offset; + NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset)); + return ndr_pull_set_offset(ndr, rel_offset); +} diff --git a/source3/libndr/ndr_basic.c b/source3/libndr/ndr_basic.c new file mode 100644 index 0000000000..31a48f67c4 --- /dev/null +++ b/source3/libndr/ndr_basic.c @@ -0,0 +1,826 @@ +/* + 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 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. +*/ + +#include "includes.h" + +/* Evil hack to convert Samba3 NTTIME's to Samba4 NTTIME's */ + +union NTTIME_big { + NTTIME s3; + uint64_t s4; +}; + + + +#define NDR_SVAL(ndr, ofs) (NDR_BE(ndr)?RSVAL(ndr->data,ofs):SVAL(ndr->data,ofs)) +#define NDR_IVAL(ndr, ofs) (NDR_BE(ndr)?RIVAL(ndr->data,ofs):IVAL(ndr->data,ofs)) +#define NDR_IVALS(ndr, ofs) (NDR_BE(ndr)?RIVALS(ndr->data,ofs):IVALS(ndr->data,ofs)) +#define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0) +#define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0) +#define NDR_SIVALS(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVALS(ndr->data,ofs,v); } else SIVALS(ndr->data,ofs,v); } while (0) + + +/* + check for data leaks from the server by looking for non-zero pad bytes + these could also indicate that real structure elements have been + mistaken for padding in the IDL +*/ +void ndr_check_padding(struct ndr_pull *ndr, size_t n) +{ + size_t ofs2 = (ndr->offset + (n-1)) & ~(n-1); + int i; + for (i=ndr->offset;idata[i] != 0) { + break; + } + } + if (ioffset;idata[i])); + } + DEBUG(0,("\n")); + } + +} + +/* + parse a int8_t +*/ +NTSTATUS ndr_pull_int8(struct ndr_pull *ndr, int ndr_flags, int8_t *v) +{ + NDR_PULL_NEED_BYTES(ndr, 1); + *v = (int8_t)CVAL(ndr->data, ndr->offset); + ndr->offset += 1; + return NT_STATUS_OK; +} + +/* + parse a uint8_t +*/ +NTSTATUS ndr_pull_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *v) +{ + NDR_PULL_NEED_BYTES(ndr, 1); + *v = CVAL(ndr->data, ndr->offset); + ndr->offset += 1; + return NT_STATUS_OK; +} + +/* + parse a int16_t +*/ +NTSTATUS ndr_pull_int16(struct ndr_pull *ndr, int ndr_flags, int16_t *v) +{ + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = (uint16_t)NDR_SVAL(ndr, ndr->offset); + ndr->offset += 2; + return NT_STATUS_OK; +} + +/* + parse a uint16_t +*/ +NTSTATUS ndr_pull_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *v) +{ + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); + *v = NDR_SVAL(ndr, ndr->offset); + ndr->offset += 2; + return NT_STATUS_OK; +} + +/* + parse a int32_t +*/ +NTSTATUS ndr_pull_int32(struct ndr_pull *ndr, int ndr_flags, int32_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_IVALS(ndr, ndr->offset); + ndr->offset += 4; + return NT_STATUS_OK; +} + +/* + parse a uint32_t +*/ +NTSTATUS ndr_pull_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); + *v = NDR_IVAL(ndr, ndr->offset); + ndr->offset += 4; + return NT_STATUS_OK; +} + +/* + parse a pointer referent identifier +*/ +NTSTATUS ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v) +{ + NTSTATUS status; + status = ndr_pull_uint32(ndr, NDR_SCALARS, v); + if (NT_STATUS_IS_OK(status) && *v != 0) { + ndr->ptr_count++; + } + return status; +} + +/* + parse a ref pointer referent identifier +*/ +NTSTATUS ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v) +{ + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, v)); + /* ref pointers always point to data */ + *v = 1; + return NT_STATUS_OK; +} + +/* + parse a udlong +*/ +NTSTATUS ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = NDR_IVAL(ndr, ndr->offset); + *v |= (uint64_t)(NDR_IVAL(ndr, ndr->offset+4)) << 32; + ndr->offset += 8; + return NT_STATUS_OK; +} + +/* + parse a udlongr +*/ +NTSTATUS ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 8); + *v = ((uint64_t)NDR_IVAL(ndr, ndr->offset)) << 32; + *v |= NDR_IVAL(ndr, ndr->offset+4); + ndr->offset += 8; + return NT_STATUS_OK; +} + +/* + parse a dlong +*/ +NTSTATUS ndr_pull_dlong(struct ndr_pull *ndr, int ndr_flags, int64_t *v) +{ + return ndr_pull_udlong(ndr, ndr_flags, (uint64_t *)v); +} + +/* + parse a hyper +*/ +NTSTATUS ndr_pull_hyper(struct ndr_pull *ndr, int ndr_flags, uint64_t *v) +{ + NDR_PULL_ALIGN(ndr, 8); + return ndr_pull_udlong(ndr, ndr_flags, v); +} + +/* + parse a pointer +*/ +NTSTATUS ndr_pull_pointer(struct ndr_pull *ndr, int ndr_flags, void* *v) +{ + intptr_t h; + NDR_PULL_ALIGN(ndr, sizeof(h)); + NDR_PULL_NEED_BYTES(ndr, sizeof(h)); + memcpy(&h, ndr->data+ndr->offset, sizeof(h)); + ndr->offset += sizeof(h); + *v = (void *)h; + return NT_STATUS_OK; +} + +/* + pull a NTSTATUS +*/ +NTSTATUS ndr_pull_NTSTATUS(struct ndr_pull *ndr, int ndr_flags, NTSTATUS *status) +{ + uint32_t v; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = NT_STATUS(v); + return NT_STATUS_OK; +} + +/* + push a NTSTATUS +*/ +NTSTATUS ndr_push_NTSTATUS(struct ndr_push *ndr, int ndr_flags, NTSTATUS status) +{ + return ndr_push_uint32(ndr, ndr_flags, NT_STATUS_V(status)); +} + +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 +*/ +NTSTATUS ndr_pull_WERROR(struct ndr_pull *ndr, int ndr_flags, WERROR *status) +{ + uint32_t v; + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v)); + *status = W_ERROR(v); + return NT_STATUS_OK; +} + +/* + push a WERROR +*/ +NTSTATUS ndr_push_WERROR(struct ndr_push *ndr, int ndr_flags, WERROR status) +{ + return ndr_push_uint32(ndr, NDR_SCALARS, W_ERROR_V(status)); +} + +void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR r) +{ + ndr->print(ndr, "%-25s: %d", name, W_ERROR_V(r)); +} + +/* + parse a set of bytes +*/ +NTSTATUS 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 NT_STATUS_OK; +} + +/* + pull an array of uint8 +*/ +NTSTATUS ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *data, uint32_t n) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + return ndr_pull_bytes(ndr, data, n); +} + +/* + push a int8_t +*/ +NTSTATUS ndr_push_int8(struct ndr_push *ndr, int ndr_flags, int8_t v) +{ + NDR_PUSH_NEED_BYTES(ndr, 1); + SCVAL(ndr->data, ndr->offset, (uint8_t)v); + ndr->offset += 1; + return NT_STATUS_OK; +} + +/* + push a uint8_t +*/ +NTSTATUS ndr_push_uint8(struct ndr_push *ndr, int ndr_flags, uint8_t v) +{ + NDR_PUSH_NEED_BYTES(ndr, 1); + SCVAL(ndr->data, ndr->offset, v); + ndr->offset += 1; + return NT_STATUS_OK; +} + +/* + push a int16_t +*/ +NTSTATUS ndr_push_int16(struct ndr_push *ndr, int ndr_flags, int16_t v) +{ + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_SSVAL(ndr, ndr->offset, (uint16_t)v); + ndr->offset += 2; + return NT_STATUS_OK; +} + +/* + push a uint16_t +*/ +NTSTATUS ndr_push_uint16(struct ndr_push *ndr, int ndr_flags, uint16_t v) +{ + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + NDR_SSVAL(ndr, ndr->offset, v); + ndr->offset += 2; + return NT_STATUS_OK; +} + +/* + push a int32_t +*/ +NTSTATUS ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_SIVALS(ndr, ndr->offset, v); + ndr->offset += 4; + return NT_STATUS_OK; +} + +/* + push a uint32_t +*/ +NTSTATUS ndr_push_uint32(struct ndr_push *ndr, int ndr_flags, uint32_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + NDR_SIVAL(ndr, ndr->offset, v); + ndr->offset += 4; + return NT_STATUS_OK; +} + +/* + push a udlong +*/ +NTSTATUS ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF)); + NDR_SIVAL(ndr, ndr->offset+4, (v>>32)); + ndr->offset += 8; + return NT_STATUS_OK; +} + +/* + push a udlongr +*/ +NTSTATUS ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 8); + NDR_SIVAL(ndr, ndr->offset, (v>>32)); + NDR_SIVAL(ndr, ndr->offset+4, (v & 0xFFFFFFFF)); + ndr->offset += 8; + return NT_STATUS_OK; +} + +/* + push a dlong +*/ +NTSTATUS ndr_push_dlong(struct ndr_push *ndr, int ndr_flags, int64_t v) +{ + return ndr_push_udlong(ndr, NDR_SCALARS, (uint64_t)v); +} + +/* + push a hyper +*/ +NTSTATUS ndr_push_hyper(struct ndr_push *ndr, int ndr_flags, uint64_t v) +{ + NDR_PUSH_ALIGN(ndr, 8); + return ndr_push_udlong(ndr, NDR_SCALARS, v); +} + +/* + push a pointer +*/ +NTSTATUS ndr_push_pointer(struct ndr_push *ndr, int ndr_flags, void* v) +{ + intptr_t h = (intptr_t)v; + NDR_PUSH_ALIGN(ndr, sizeof(h)); + NDR_PUSH_NEED_BYTES(ndr, sizeof(h)); + memcpy(ndr->data+ndr->offset, &h, sizeof(h)); + ndr->offset += sizeof(h); + return NT_STATUS_OK; +} + +NTSTATUS ndr_push_align(struct ndr_push *ndr, size_t size) +{ + NDR_PUSH_ALIGN(ndr, size); + return NT_STATUS_OK; +} + +NTSTATUS ndr_pull_align(struct ndr_pull *ndr, size_t size) +{ + NDR_PULL_ALIGN(ndr, size); + return NT_STATUS_OK; +} + +/* + push some bytes +*/ +NTSTATUS ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n) +{ + NDR_PUSH_NEED_BYTES(ndr, n); + memcpy(ndr->data + ndr->offset, data, n); + ndr->offset += n; + return NT_STATUS_OK; +} + +/* + push some zero bytes +*/ +NTSTATUS 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 NT_STATUS_OK; +} + +/* + push an array of uint8 +*/ +NTSTATUS ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const uint8_t *data, uint32_t n) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + return ndr_push_bytes(ndr, data, n); +} + +/* + save the current position + */ +void ndr_push_save(struct ndr_push *ndr, struct ndr_push_save *save) +{ + save->offset = ndr->offset; +} + +/* + restore the position + */ +void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save) +{ + ndr->offset = save->offset; +} + +/* + push a unique non-zero value if a pointer is non-NULL, otherwise 0 +*/ +NTSTATUS ndr_push_unique_ptr(struct ndr_push *ndr, const void *p) +{ + uint32_t ptr = 0; + if (p) { + ptr = ndr->ptr_count * 4; + ptr |= 0x00020000; + ndr->ptr_count++; + } + return ndr_push_uint32(ndr, NDR_SCALARS, ptr); +} + +/* + push a 'simple' full non-zero value if a pointer is non-NULL, otherwise 0 +*/ +NTSTATUS ndr_push_sptr_ptr(struct ndr_push *ndr, const void *p) +{ + uint32_t ptr = 0; + if (p) { + ndr->ptr_count++; + ptr = ndr->ptr_count; + } + return ndr_push_uint32(ndr, NDR_SCALARS, ptr); +} + +/* + push always a 0, if a pointer is NULL it's a fatal error +*/ +NTSTATUS ndr_push_ref_ptr(struct ndr_push *ndr, const void *p) +{ + if (p == NULL) { + return NT_STATUS_INVALID_PARAMETER_MIX; + } + return ndr_push_uint32(ndr, NDR_SCALARS, 0xAEF1AEF1); +} + +/* + push a NTTIME +*/ +NTSTATUS ndr_push_NTTIME(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + union NTTIME_big b; b.s3 = t; + NDR_CHECK(ndr_push_udlong(ndr, ndr_flags, b.s4)); + return NT_STATUS_OK; +} + +/* + pull a NTTIME +*/ +NTSTATUS ndr_pull_NTTIME(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + union NTTIME_big b; + NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, &b.s4)); + + *t = b.s3; + return NT_STATUS_OK; +} + +/* + push a NTTIME +*/ +NTSTATUS ndr_push_NTTIME_1sec(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + union NTTIME_big b; b.s3 = t; + + b.s4 /= 10000000; + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, b.s4)); + return NT_STATUS_OK; +} + +/* + pull a NTTIME_1sec +*/ +NTSTATUS ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + union NTTIME_big b; + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &b.s4)); + b.s4 *= 10000000; + *t = b.s3; + return NT_STATUS_OK; +} + +/* + pull a NTTIME_hyper +*/ +NTSTATUS ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, int ndr_flags, NTTIME *t) +{ + union NTTIME_big b; + NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &b.s4)); + *t = b.s3; + return NT_STATUS_OK; +} + +/* + push a NTTIME_hyper +*/ +NTSTATUS ndr_push_NTTIME_hyper(struct ndr_push *ndr, int ndr_flags, NTTIME t) +{ + union NTTIME_big b; b.s3 = t; + NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, b.s4)); + return NT_STATUS_OK; +} + +/* + push a time_t +*/ +NTSTATUS ndr_push_time_t(struct ndr_push *ndr, int ndr_flags, time_t t) +{ + return ndr_push_uint32(ndr, ndr_flags, t); +} + +/* + pull a time_t +*/ +NTSTATUS ndr_pull_time_t(struct ndr_pull *ndr, int ndr_flags, time_t *t) +{ + uint32_t tt; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &tt)); + *t = tt; + return NT_STATUS_OK; +} + + +void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type) +{ + ndr->print(ndr, "%s: struct %s", name, type); +} + +void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type, + const char *val, uint32_t value) +{ + if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) { + ndr->print(ndr, "%-25s: %s (0x%X)", name, val?val:"UNKNOWN_ENUM_VALUE", value); + } else { + ndr->print(ndr, "%-25s: %s (%d)", name, val?val:"UNKNOWN_ENUM_VALUE", value); + } +} + +void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value) +{ + /* this is an attempt to support multi-bit bitmap masks */ + value &= flag; + + while (!(flag & 1)) { + flag >>= 1; + value >>= 1; + } + if (flag == 1) { + ndr->print(ndr, " %d: %-25s", value, flag_name); + } else { + ndr->print(ndr, "0x%02x: %-25s (%d)", value, flag_name, value); + } +} + +void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v) +{ + ndr->print(ndr, "%-25s: 0x%02x (%u)", name, v, v); +} + +void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v) +{ + ndr->print(ndr, "%-25s: 0x%04x (%u)", name, v, v); +} + +void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v) +{ + ndr->print(ndr, "%-25s: %d", name, v); +} + +void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v) +{ + ndr->print(ndr, "%-25s: 0x%08x (%u)", name, v, v); +} + +void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr->print(ndr, "%-25s: 0x%016llx (%llu)", name, v, v); +} + +void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr_print_udlong(ndr, name, v); +} + +void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v) +{ + ndr->print(ndr, "%-25s: 0x%016llx (%lld)", name, v, v); +} + +void ndr_print_hyper(struct ndr_print *ndr, const char *name, uint64_t v) +{ + ndr_print_dlong(ndr, name, v); +} + +void ndr_print_pointer(struct ndr_print *ndr, const char *name, void *v) +{ + ndr->print(ndr, "%-25s: %p", name, v); +} + +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); + } +} + +void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t) +{ + ndr->print(ndr, "%-25s: %s", name, nt_time_string(ndr, t)); +} + +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); +} + +void ndr_print_NTTIME_hyper(struct ndr_print *ndr, const char *name, NTTIME t) +{ + ndr_print_NTTIME(ndr, name, t); +} + +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)); + } +} + +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); + } +} + +void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level) +{ + ndr->print(ndr, "UNKNOWN LEVEL %u", level); +} + +void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, + const uint8_t *data, uint32_t count) +{ + int i; + + if (count <= 600 && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) { + char s[1202]; + for (i=0;iprint(ndr, "%-25s: %s", name, s); + return; + } + + ndr->print(ndr, "%s: ARRAY(%d)", name, count); + ndr->depth++; + for (i=0;idepth--; +} + +void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r) +{ + ndr->print(ndr, "%-25s: DATA_BLOB length=%u", name, r.length); + if (r.length) { + dump_data(10, (const char *)r.data, r.length); + } +} + + +/* + push a DATA_BLOB onto the wire. +*/ +NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flags, DATA_BLOB blob) +{ + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + blob.length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + blob.length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + blob.length = NDR_ALIGN(ndr, 8); + } + NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length); + data_blob_clear(&blob); + } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, blob.length)); + } + NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length)); + return NT_STATUS_OK; +} + +/* + pull a DATA_BLOB from the wire. +*/ +NTSTATUS ndr_pull_DATA_BLOB(struct ndr_pull *ndr, int ndr_flags, DATA_BLOB *blob) +{ + uint32_t length = 0; + + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + length = NDR_ALIGN(ndr, 8); + } + if (ndr->data_size - ndr->offset < length) { + length = ndr->data_size - ndr->offset; + } + } else if (ndr->flags & LIBNDR_FLAG_REMAINING) { + length = ndr->data_size - ndr->offset; + } else { + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length)); + } + NDR_PULL_NEED_BYTES(ndr, length); + *blob = data_blob_talloc(ndr->current_mem_ctx, ndr->data+ndr->offset, length); + ndr->offset += length; + return NT_STATUS_OK; +} + +uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, int flags) +{ + return ret + data->length; +} diff --git a/source3/libndr/ndr_misc.c b/source3/libndr/ndr_misc.c new file mode 100644 index 0000000000..2f9004ae66 --- /dev/null +++ b/source3/libndr/ndr_misc.c @@ -0,0 +1,171 @@ +/* + Unix SMB/CIFS implementation. + + UUID/GUID/policy_handle functions + + Copyright (C) Theodore Ts'o 1996, 1997, + Copyright (C) Jim McDonough 2002. + Copyright (C) Andrew Tridgell 2003. + Copyright (C) Stefan (metze) Metzmacher 2004. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. +*/ + +#include "includes.h" + +/** + build a GUID from a string +*/ +NTSTATUS GUID_from_string(const char *s, struct GUID *guid) +{ + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; + uint32_t time_low; + uint32_t time_mid, time_hi_and_version; + uint32_t clock_seq[2]; + uint32_t node[6]; + int i; + + if (s == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (11 == sscanf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq[0], &clock_seq[1], + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + status = NT_STATUS_OK; + } else if (11 == sscanf(s, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq[0], &clock_seq[1], + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + status = NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + guid->time_low = time_low; + guid->time_mid = time_mid; + guid->time_hi_and_version = time_hi_and_version; + guid->clock_seq[0] = clock_seq[0]; + guid->clock_seq[1] = clock_seq[1]; + for (i=0;i<6;i++) { + guid->node[i] = node[i]; + } + + return NT_STATUS_OK; +} + +/** + * generate a random GUID + */ +struct GUID GUID_random(void) +{ + struct GUID guid; + + generate_random_buffer((uint8_t *)&guid, sizeof(guid)); + guid.clock_seq[0] = (guid.clock_seq[0] & 0x3F) | 0x80; + guid.time_hi_and_version = (guid.time_hi_and_version & 0x0FFF) | 0x4000; + + return guid; +} + +/** + * generate an empty GUID + */ +struct GUID GUID_zero(void) +{ + struct GUID guid; + + ZERO_STRUCT(guid); + + return guid; +} + +/** + * see if a range of memory is all zero. A NULL pointer is considered + * to be all zero + */ +BOOL all_zero(const uint8_t *ptr, size_t size) +{ + int i; + if (!ptr) return True; + for (i=0;itime_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; +} + +BOOL GUID_equal(const struct GUID *u1, const struct GUID *u2) +{ + if (u1->time_low != u2->time_low || + u1->time_mid != u2->time_mid || + u1->time_hi_and_version != u2->time_hi_and_version || + u1->clock_seq[0] != u2->clock_seq[0] || + u1->clock_seq[1] != u2->clock_seq[1] || + memcmp(u1->node, u2->node, 6) != 0) { + return False; + } + return True; +} + +/** + its useful to be able to display these in debugging messages +*/ +char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + return talloc_asprintf(mem_ctx, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->time_low, guid->time_mid, + guid->time_hi_and_version, + guid->clock_seq[0], + guid->clock_seq[1], + guid->node[0], guid->node[1], + guid->node[2], guid->node[3], + guid->node[4], guid->node[5]); +} + +char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid) +{ + char *ret, *s = GUID_string(mem_ctx, guid); + ret = talloc_asprintf(mem_ctx, "{%s}", s); + talloc_free(s); + return ret; +} + +void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid) +{ + ndr->print(ndr, "%-25s: %s", name, GUID_string(ndr, guid)); +} + +BOOL policy_handle_empty(struct policy_handle *h) +{ + return (h->handle_type == 0 && GUID_all_zero(&h->uuid)); +} diff --git a/source3/libndr/ndr_sec.h b/source3/libndr/ndr_sec.h new file mode 100644 index 0000000000..0858eac72c --- /dev/null +++ b/source3/libndr/ndr_sec.h @@ -0,0 +1,35 @@ +#ifndef __LIBRPC_NDR_NDR_SEC_H__ +#define __LIBRPC_NDR_NDR_SEC_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +#ifndef _PUBLIC_ +#define _PUBLIC_ +#endif + + +/* The following definitions come from librpc/ndr/ndr_sec_helper.c */ + +size_t ndr_size_dom_sid(const struct dom_sid *sid); +size_t ndr_length_dom_sid(const struct dom_sid *sid); +size_t ndr_size_security_ace(const struct security_ace *ace); +size_t ndr_size_security_acl(const struct security_acl *acl); +size_t ndr_size_security_descriptor(const struct security_descriptor *sd); +void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid); +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); + +/* The following definitions come from librpc/ndr/ndr_sec.c */ + +NTSTATUS ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid); +NTSTATUS ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid); +NTSTATUS ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid); +NTSTATUS ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __LIBRPC_NDR_NDR_SEC_H__ */ + diff --git a/source3/libndr/ndr_sec_helper.c b/source3/libndr/ndr_sec_helper.c new file mode 100644 index 0000000000..edbdd9a40e --- /dev/null +++ b/source3/libndr/ndr_sec_helper.c @@ -0,0 +1,187 @@ +/* + Unix SMB/CIFS implementation. + + fast routines for getting the wire size of security objects + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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. +*/ + + +#include "includes.h" + +/* + return the wire size of a dom_sid +*/ +size_t ndr_size_dom_sid(const struct dom_sid *sid, int flags) +{ + if (!sid) return 0; + return 8 + 4*sid->num_auths; +} + +/* + return the wire size of a security_ace +*/ +size_t ndr_size_security_ace(const struct security_ace *ace, int flags) +{ + if (!ace) return 0; + return 8 + ndr_size_dom_sid(&ace->trustee, flags); +} + + +/* + return the wire size of a security_acl +*/ +size_t ndr_size_security_acl(const struct security_acl *acl, int flags) +{ + size_t ret; + int i; + if (!acl) return 0; + ret = 8; + for (i=0;inum_aces;i++) { + ret += ndr_size_security_ace(&acl->aces[i], flags); + } + return ret; +} + +/* + return the wire size of a security descriptor +*/ +size_t ndr_size_security_descriptor(const struct security_descriptor *sd, int flags) +{ + size_t ret; + if (!sd) return 0; + + ret = 20; + ret += ndr_size_dom_sid(sd->owner_sid, flags); + ret += ndr_size_dom_sid(sd->group_sid, flags); + ret += ndr_size_security_acl(sd->dacl, flags); + ret += ndr_size_security_acl(sd->sacl, flags); + return ret; +} + +/* + print a dom_sid +*/ +void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr->print(ndr, "%-25s: %s", name, dom_sid_string(ndr, sid)); +} + +void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr_print_dom_sid(ndr, name, sid); +} + +void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid) +{ + ndr_print_dom_sid(ndr, name, sid); +} + + +/* + parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field +*/ +NTSTATUS ndr_pull_dom_sid2(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) +{ + uint32_t num_auths; + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &num_auths)); + NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid)); + if (sid->num_auths != num_auths) { + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, + "Bad array size %u should exceed %u", + num_auths, sid->num_auths); + } + return NT_STATUS_OK; +} + +/* + parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field +*/ +NTSTATUS ndr_push_dom_sid2(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid) +{ + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, sid->num_auths)); + return ndr_push_dom_sid(ndr, ndr_flags, sid); +} + +/* + parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth +*/ +NTSTATUS ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) +{ + NTSTATUS status; + struct ndr_pull *subndr; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + subndr = talloc_zero(ndr, struct ndr_pull); + NT_STATUS_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags; + subndr->current_mem_ctx = ndr->current_mem_ctx; + + subndr->data = ndr->data + ndr->offset; + subndr->data_size = 28; + subndr->offset = 0; + + NDR_CHECK(ndr_pull_advance(ndr, 28)); + + status = ndr_pull_dom_sid(subndr, ndr_flags, sid); + if (!NT_STATUS_IS_OK(status)) { + /* handle a w2k bug which send random data in the buffer */ + ZERO_STRUCTP(sid); + } + + return NT_STATUS_OK; +} + +/* + push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer +*/ +NTSTATUS ndr_push_dom_sid28(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *sid) +{ + uint32_t old_offset; + uint32_t padding; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + if (sid->num_auths > 5) { + return ndr_push_error(ndr, NDR_ERR_RANGE, + "dom_sid28 allows only upto 5 sub auth [%u]", + sid->num_auths); + } + + old_offset = ndr->offset; + NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid)); + + padding = 28 - (ndr->offset - old_offset); + + if (padding > 0) { + NDR_CHECK(ndr_push_zero(ndr, padding)); + } + + return NT_STATUS_OK; +} + diff --git a/source3/libndr/ndr_string.c b/source3/libndr/ndr_string.c new file mode 100644 index 0000000000..d6c842a653 --- /dev/null +++ b/source3/libndr/ndr_string.c @@ -0,0 +1,612 @@ +/* + 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 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. +*/ + +#include "includes.h" + +/** + pull a general string from the wire +*/ +NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) +{ + char *as=NULL; + uint32_t len1, ofs, len2; + uint16_t len3; + int ret; + charset_t chset = CH_UCS2; + unsigned byte_mul = 2; + unsigned flags = ndr->flags; + unsigned c_len_term = 0; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + SMB_ASSERT(!NDR_BE(ndr)); + + if (flags & LIBNDR_FLAG_STR_ASCII) { + chset = CH_DOS; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_ASCII; + } + + if (flags & LIBNDR_FLAG_STR_UTF8) { + chset = CH_UTF8; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_UTF8; + } + + flags &= ~LIBNDR_FLAG_STR_CONFORMANT; + if (flags & LIBNDR_FLAG_STR_CHARLEN) { + c_len_term = 1; + flags &= ~LIBNDR_FLAG_STR_CHARLEN; + } + + switch (flags & LIBNDR_STRING_FLAGS) { + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); + if (ofs != 0) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2)); + if (len2 > len1) { + return ndr_pull_error(ndr, NDR_ERR_STRING, + "Bad string lengths len1=%u ofs=%u len2=%u\n", + len1, ofs, len2); + } + NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul); + if (len2 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + (len2 + c_len_term)*byte_mul, + &as, True); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul)); + + if (len1 != len2) { + DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as)); + } + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len2 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len2 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_SIZE4: + case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); + if (len1 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + (len1 + c_len_term)*byte_mul, + &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len1 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len1 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_LEN4: + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); + if (ofs != 0) { + return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); + NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); + if (len1 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + (len1 + c_len_term)*byte_mul, + &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len1 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len1 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + + case LIBNDR_FLAG_STR_SIZE2: + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul); + if (len3 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + (len3 + c_len_term)*byte_mul, + &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul)); + + /* this is a way of detecting if a string is sent with the wrong + termination */ + if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { + if (strlen(as) < (len3 + c_len_term)) { + DEBUG(6,("short string '%s'\n", as)); + } + } else { + if (strlen(as) == (len3 + c_len_term)) { + DEBUG(6,("long string '%s'\n", as)); + } + } + *s = as; + break; + + case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); + NDR_PULL_NEED_BYTES(ndr, len3); + if (len3 == 0) { + as = talloc_strdup(ndr->current_mem_ctx, ""); + } else { + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + len3, &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + } + NDR_CHECK(ndr_pull_advance(ndr, len3)); + *s = as; + break; + + case LIBNDR_FLAG_STR_NULLTERM: + if (byte_mul == 1) { + len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); + } else { + len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); + } + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + len1, &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, len1)); + *s = as; + break; + + case LIBNDR_FLAG_STR_FIXLEN15: + case LIBNDR_FLAG_STR_FIXLEN32: + len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; + NDR_PULL_NEED_BYTES(ndr, len1*byte_mul); + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + len1*byte_mul, &as, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul)); + *s = as; + break; + + default: + return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + return NT_STATUS_OK; +} + + +/** + push a general string onto the wire +*/ +NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) +{ + ssize_t s_len, c_len, d_len; + charset_t chset = CH_UCS2; + unsigned flags = ndr->flags; + unsigned byte_mul = 2; + uint8_t *dest = NULL; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + SMB_ASSERT(!NDR_BE(ndr)); + + s_len = s?strlen(s):0; + + if (flags & LIBNDR_FLAG_STR_ASCII) { + chset = CH_DOS; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_ASCII; + } + + if (flags & LIBNDR_FLAG_STR_UTF8) { + chset = CH_UTF8; + byte_mul = 1; + flags &= ~LIBNDR_FLAG_STR_UTF8; + } + + flags &= ~LIBNDR_FLAG_STR_CONFORMANT; + + if (!(flags & + (LIBNDR_FLAG_STR_NOTERM | + LIBNDR_FLAG_STR_FIXLEN15 | + LIBNDR_FLAG_STR_FIXLEN32))) { + s_len++; + } + d_len = convert_string_talloc(ndr, CH_UNIX, chset, s, s_len, &dest, + False); + if (d_len == -1) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + + if (flags & LIBNDR_FLAG_STR_BYTESIZE) { + c_len = d_len; + flags &= ~LIBNDR_FLAG_STR_BYTESIZE; + } else if (flags & LIBNDR_FLAG_STR_CHARLEN) { + c_len = (d_len / byte_mul)-1; + flags &= ~LIBNDR_FLAG_STR_CHARLEN; + } else { + c_len = d_len / byte_mul; + } + + switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) { + case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_LEN4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_SIZE4: + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len)); + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_NULLTERM: + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + break; + + case LIBNDR_FLAG_STR_FIXLEN15: + case LIBNDR_FLAG_STR_FIXLEN32: { + ssize_t fix_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; + uint32_t pad_len = fix_len - d_len; + if (d_len > fix_len) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); + if (pad_len != 0) { + NDR_CHECK(ndr_push_zero(ndr, pad_len)); + } + break; + } + + default: + return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", + ndr->flags & LIBNDR_STRING_FLAGS); + } + + talloc_free(dest); + + return NT_STATUS_OK; +} + +/** + push a general string onto the wire +*/ +size_t ndr_string_array_size(struct ndr_push *ndr, const char *s) +{ + size_t c_len; + unsigned flags = ndr->flags; + unsigned byte_mul = 2; + unsigned c_len_term = 1; + + if (flags & LIBNDR_FLAG_STR_FIXLEN32) { + return 32; + } + if (flags & LIBNDR_FLAG_STR_FIXLEN15) { + return 15; + } + + c_len = s?strlen(s):0; + + if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) { + byte_mul = 1; + } + + if (flags & LIBNDR_FLAG_STR_NOTERM) { + c_len_term = 0; + } + + c_len = c_len + c_len_term; + + if (flags & LIBNDR_FLAG_STR_BYTESIZE) { + c_len = c_len * byte_mul; + } + + return c_len; +} + +void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s) +{ + if (s) { + ndr->print(ndr, "%-25s: '%s'", name, s); + } else { + ndr->print(ndr, "%-25s: NULL", name); + } +} + +uint32_t ndr_size_string(int ret, const char * const* string, int flags) +{ + /* FIXME: Is this correct for all strings ? */ + if(!(*string)) return ret; + return ret+strlen(*string)+1; +} + +/** + pull a general string array from the wire +*/ +NTSTATUS ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a) +{ + const char **a = *_a; + uint32_t count; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + for (count = 0;; count++) { + TALLOC_CTX *tmp_ctx; + const char *s = NULL; + a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2); + NT_STATUS_HAVE_NO_MEMORY(a); + a[count] = NULL; + a[count+1] = NULL; + + tmp_ctx = ndr->current_mem_ctx; + ndr->current_mem_ctx = a; + NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); + ndr->current_mem_ctx = tmp_ctx; + if (strcmp("", s)==0) { + a[count] = NULL; + break; + } else { + a[count] = s; + } + } + + *_a =a; + return NT_STATUS_OK; +} + +/** + push a general string array onto the wire +*/ +NTSTATUS ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a) +{ + uint32_t count; + + if (!(ndr_flags & NDR_SCALARS)) { + return NT_STATUS_OK; + } + + for (count = 0; a && a[count]; count++) { + NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); + } + + NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); + + return NT_STATUS_OK; +} + +void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a) +{ + uint32_t count; + uint32_t i; + + for (count = 0; a && a[count]; count++) {} + + ndr->print(ndr, "%s: ARRAY(%d)", name, count); + ndr->depth++; + for (i=0;idepth--; +} + +/** + * Return number of elements in a string including the last (zeroed) element + */ +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; +} + +NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) +{ + uint32_t i; + struct ndr_pull_save save_offset; + + ndr_pull_save(ndr, &save_offset); + ndr_pull_advance(ndr, (count - 1) * element_size); + NDR_PULL_NEED_BYTES(ndr, element_size); + + for (i = 0; i < element_size; i++) { + if (ndr->data[ndr->offset+i] != 0) { + ndr_pull_restore(ndr, &save_offset); + + return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); + } + } + + ndr_pull_restore(ndr, &save_offset); + + return NT_STATUS_OK; +} + +NTSTATUS ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, int chset) +{ + int ret; + if (length == 0) { + *var = talloc_strdup(ndr->current_mem_ctx, ""); + return NT_STATUS_OK; + } + + SMB_ASSERT (!NDR_BE(ndr) || chset != CH_UCS2); + + NDR_PULL_NEED_BYTES(ndr, length*byte_mul); + + ret = convert_string_talloc(ndr->current_mem_ctx, + chset, CH_UNIX, + ndr->data+ndr->offset, + length*byte_mul, + var, False); + if (ret == -1) { + return ndr_pull_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); + + return NT_STATUS_OK; +} + +NTSTATUS ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, + uint32_t length, uint8_t byte_mul, charset_t chset) +{ + ssize_t ret, required; + + SMB_ASSERT(!NDR_BE(ndr) || chset != CH_UCS2); + + required = byte_mul * length; + + NDR_PUSH_NEED_BYTES(ndr, required); + ret = convert_string(CH_UNIX, chset, + var, strlen(var), + ndr->data+ndr->offset, required, False); + if (ret == -1) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + + /* Make sure the remaining part of the string is filled with zeroes */ + if (ret < required) { + memset(ndr->data+ndr->offset+ret, 0, required-ret); + } + + ndr->offset += required; + + return NT_STATUS_OK; +} + +/* Return number of elements in a string in the specified charset */ +uint32_t ndr_charset_length(const void *var, int chset) +{ + /* FIXME: Treat special chars special here, taking chset into account */ + /* Also include 0 byte */ + return strlen((const char *)var)+1; +} diff --git a/source3/libndr/security.h b/source3/libndr/security.h new file mode 100644 index 0000000000..8f790f387e --- /dev/null +++ b/source3/libndr/security.h @@ -0,0 +1,260 @@ +/* header auto-generated by pidl */ + +#ifndef _HEADER_security +#define _HEADER_security + +#define SEC_MASK_GENERIC ( 0xF0000000 ) +#define SEC_MASK_FLAGS ( 0x0F000000 ) +#define SEC_MASK_STANDARD ( 0x00FF0000 ) +#define SEC_MASK_SPECIFIC ( 0x0000FFFF ) +#define SEC_GENERIC_ALL ( 0x10000000 ) +#define SEC_GENERIC_EXECUTE ( 0x20000000 ) +#define SEC_GENERIC_WRITE ( 0x40000000 ) +#define SEC_GENERIC_READ ( 0x80000000 ) +#define SEC_FLAG_SYSTEM_SECURITY ( 0x01000000 ) +#define SEC_FLAG_MAXIMUM_ALLOWED ( 0x02000000 ) +#define SEC_STD_DELETE ( 0x00010000 ) +#define SEC_STD_READ_CONTROL ( 0x00020000 ) +#define SEC_STD_WRITE_DAC ( 0x00040000 ) +#define SEC_STD_WRITE_OWNER ( 0x00080000 ) +#define SEC_STD_SYNCHRONIZE ( 0x00100000 ) +#define SEC_STD_REQUIRED ( 0x000F0000 ) +#define SEC_STD_ALL ( 0x001F0000 ) +#define SEC_FILE_READ_DATA ( 0x00000001 ) +#define SEC_FILE_WRITE_DATA ( 0x00000002 ) +#define SEC_FILE_APPEND_DATA ( 0x00000004 ) +#define SEC_FILE_READ_EA ( 0x00000008 ) +#define SEC_FILE_WRITE_EA ( 0x00000010 ) +#define SEC_FILE_EXECUTE ( 0x00000020 ) +#define SEC_FILE_READ_ATTRIBUTE ( 0x00000080 ) +#define SEC_FILE_WRITE_ATTRIBUTE ( 0x00000100 ) +#define SEC_FILE_ALL ( 0x000001ff ) +#define SEC_DIR_LIST ( 0x00000001 ) +#define SEC_DIR_ADD_FILE ( 0x00000002 ) +#define SEC_DIR_ADD_SUBDIR ( 0x00000004 ) +#define SEC_DIR_READ_EA ( 0x00000008 ) +#define SEC_DIR_WRITE_EA ( 0x00000010 ) +#define SEC_DIR_TRAVERSE ( 0x00000020 ) +#define SEC_DIR_DELETE_CHILD ( 0x00000040 ) +#define SEC_DIR_READ_ATTRIBUTE ( 0x00000080 ) +#define SEC_DIR_WRITE_ATTRIBUTE ( 0x00000100 ) +#define SEC_REG_QUERY_VALUE ( 0x00000001 ) +#define SEC_REG_SET_VALUE ( 0x00000002 ) +#define SEC_REG_CREATE_SUBKEY ( 0x00000004 ) +#define SEC_REG_ENUM_SUBKEYS ( 0x00000008 ) +#define SEC_REG_NOTIFY ( 0x00000010 ) +#define SEC_REG_CREATE_LINK ( 0x00000020 ) +#define SEC_ADS_CREATE_CHILD ( 0x00000001 ) +#define SEC_ADS_DELETE_CHILD ( 0x00000002 ) +#define SEC_ADS_LIST ( 0x00000004 ) +#define SEC_ADS_SELF_WRITE ( 0x00000008 ) +#define SEC_ADS_READ_PROP ( 0x00000010 ) +#define SEC_ADS_WRITE_PROP ( 0x00000020 ) +#define SEC_ADS_DELETE_TREE ( 0x00000040 ) +#define SEC_ADS_LIST_OBJECT ( 0x00000080 ) +#define SEC_ADS_CONTROL_ACCESS ( 0x00000100 ) +#define SEC_RIGHTS_FILE_READ ( SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_READ_EA ) +#define SEC_RIGHTS_FILE_WRITE ( SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE|SEC_FILE_WRITE_EA|SEC_FILE_APPEND_DATA ) +#define SEC_RIGHTS_FILE_EXECUTE ( SEC_STD_SYNCHRONIZE|SEC_STD_READ_CONTROL|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_EXECUTE ) +#define SEC_RIGHTS_FILE_ALL ( SEC_STD_ALL|SEC_FILE_ALL ) +#define SEC_RIGHTS_DIR_READ ( SEC_RIGHTS_FILE_READ ) +#define SEC_RIGHTS_DIR_WRITE ( SEC_RIGHTS_FILE_WRITE ) +#define SEC_RIGHTS_DIR_EXECUTE ( SEC_RIGHTS_FILE_EXECUTE ) +#define SEC_RIGHTS_DIR_ALL ( SEC_RIGHTS_FILE_ALL ) +#define SID_NULL ( "S-1-0-0" ) +#define SID_WORLD_DOMAIN ( "S-1-1" ) +#define SID_WORLD ( "S-1-1-0" ) +#define SID_CREATOR_OWNER_DOMAIN ( "S-1-3" ) +#define SID_CREATOR_OWNER ( "S-1-3-0" ) +#define SID_CREATOR_GROUP ( "S-1-3-1" ) +#define SID_NT_AUTHORITY ( "S-1-5" ) +#define SID_NT_DIALUP ( "S-1-5-1" ) +#define SID_NT_NETWORK ( "S-1-5-2" ) +#define SID_NT_BATCH ( "S-1-5-3" ) +#define SID_NT_INTERACTIVE ( "S-1-5-4" ) +#define SID_NT_SERVICE ( "S-1-5-6" ) +#define SID_NT_ANONYMOUS ( "S-1-5-7" ) +#define SID_NT_PROXY ( "S-1-5-8" ) +#define SID_NT_ENTERPRISE_DCS ( "S-1-5-9" ) +#define SID_NT_SELF ( "S-1-5-10" ) +#define SID_NT_AUTHENTICATED_USERS ( "S-1-5-11" ) +#define SID_NT_RESTRICTED ( "S-1-5-12" ) +#define SID_NT_TERMINAL_SERVER_USERS ( "S-1-5-13" ) +#define SID_NT_REMOTE_INTERACTIVE ( "S-1-5-14" ) +#define SID_NT_THIS_ORGANISATION ( "S-1-5-15" ) +#define SID_NT_SYSTEM ( "S-1-5-18" ) +#define SID_NT_LOCAL_SERVICE ( "S-1-5-19" ) +#define SID_NT_NETWORK_SERVICE ( "S-1-5-20" ) +#define SID_BUILTIN ( "S-1-5-32" ) +#define SID_BUILTIN_ADMINISTRATORS ( "S-1-5-32-544" ) +#define SID_BUILTIN_USERS ( "S-1-5-32-545" ) +#define SID_BUILTIN_GUESTS ( "S-1-5-32-546" ) +#define SID_BUILTIN_POWER_USERS ( "S-1-5-32-547" ) +#define SID_BUILTIN_ACCOUNT_OPERATORS ( "S-1-5-32-548" ) +#define SID_BUILTIN_SERVER_OPERATORS ( "S-1-5-32-549" ) +#define SID_BUILTIN_PRINT_OPERATORS ( "S-1-5-32-550" ) +#define SID_BUILTIN_BACKUP_OPERATORS ( "S-1-5-32-551" ) +#define SID_BUILTIN_REPLICATOR ( "S-1-5-32-552" ) +#define SID_BUILTIN_RAS_SERVERS ( "S-1-5-32-553" ) +#define SID_BUILTIN_PREW2K ( "S-1-5-32-554" ) +#define DOMAIN_RID_LOGON ( 9 ) +#define DOMAIN_RID_ADMINISTRATOR ( 500 ) +#define DOMAIN_RID_GUEST ( 501 ) +#define DOMAIN_RID_ADMINS ( 512 ) +#define DOMAIN_RID_USERS ( 513 ) +#define DOMAIN_RID_DCS ( 516 ) +#define DOMAIN_RID_CERT_ADMINS ( 517 ) +#define DOMAIN_RID_SCHEMA_ADMINS ( 518 ) +#define DOMAIN_RID_ENTERPRISE_ADMINS ( 519 ) +#define NT4_ACL_REVISION ( SECURITY_ACL_REVISION_NT4 ) +#define SD_REVISION ( SECURITY_DESCRIPTOR_REVISION_1 ) +enum sec_privilege { + SEC_PRIV_SECURITY=1, + SEC_PRIV_BACKUP=2, + SEC_PRIV_RESTORE=3, + SEC_PRIV_SYSTEMTIME=4, + SEC_PRIV_SHUTDOWN=5, + SEC_PRIV_REMOTE_SHUTDOWN=6, + SEC_PRIV_TAKE_OWNERSHIP=7, + SEC_PRIV_DEBUG=8, + SEC_PRIV_SYSTEM_ENVIRONMENT=9, + SEC_PRIV_SYSTEM_PROFILE=10, + SEC_PRIV_PROFILE_SINGLE_PROCESS=11, + SEC_PRIV_INCREASE_BASE_PRIORITY=12, + SEC_PRIV_LOAD_DRIVER=13, + SEC_PRIV_CREATE_PAGEFILE=14, + SEC_PRIV_INCREASE_QUOTA=15, + SEC_PRIV_CHANGE_NOTIFY=16, + SEC_PRIV_UNDOCK=17, + SEC_PRIV_MANAGE_VOLUME=18, + SEC_PRIV_IMPERSONATE=19, + SEC_PRIV_CREATE_GLOBAL=20, + SEC_PRIV_ENABLE_DELEGATION=21, + SEC_PRIV_INTERACTIVE_LOGON=22, + SEC_PRIV_NETWORK_LOGON=23, + SEC_PRIV_REMOTE_INTERACTIVE_LOGON=24 +}; + +struct dom_sid { + uint8_t sid_rev_num; + int8_t num_auths;/* [range(0 15)] */ + uint8_t id_auth[6]; + uint32_t *sub_auths; +}/* [noprint,gensize,noejs,public,nosize] */; + +/* bitmap security_ace_flags */ +#define SEC_ACE_FLAG_OBJECT_INHERIT ( 0x01 ) +#define SEC_ACE_FLAG_CONTAINER_INHERIT ( 0x02 ) +#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ( 0x04 ) +#define SEC_ACE_FLAG_INHERIT_ONLY ( 0x08 ) +#define SEC_ACE_FLAG_INHERITED_ACE ( 0x10 ) +#define SEC_ACE_FLAG_VALID_INHERIT ( 0x0f ) +#define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 ) +#define SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) + +enum security_ace_type { + SEC_ACE_TYPE_ACCESS_ALLOWED=0, + SEC_ACE_TYPE_ACCESS_DENIED=1, + SEC_ACE_TYPE_SYSTEM_AUDIT=2, + SEC_ACE_TYPE_SYSTEM_ALARM=3, + SEC_ACE_TYPE_ALLOWED_COMPOUND=4, + SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT=5, + SEC_ACE_TYPE_ACCESS_DENIED_OBJECT=6, + SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT=7, + SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT=8 +}; + +/* bitmap security_ace_object_flags */ +#define SEC_ACE_OBJECT_TYPE_PRESENT ( 0x00000001 ) +#define SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT ( 0x00000002 ) + +union security_ace_object_type { + struct GUID type;/* [case(SEC_ACE_OBJECT_TYPE_PRESENT)] */ +}/* [nodiscriminant] */; + +union security_ace_object_inherited_type { + struct GUID inherited_type;/* [case(SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] */ +}/* [nodiscriminant] */; + +struct security_ace_object { + uint32_t flags; + union security_ace_object_type type;/* [switch_is(flags&SEC_ACE_OBJECT_TYPE_PRESENT)] */ + union security_ace_object_inherited_type inherited_type;/* [switch_is(flags&SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] */ +}; + +union security_ace_object_ctr { + struct security_ace_object object;/* [case(SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT)] */ +}/* [nodiscriminant] */; + +struct security_ace { + enum security_ace_type type; + uint8_t flags; + uint16_t size;/* [value(ndr_size_security_ace(r,ndr->flags))] */ + uint32_t access_mask; + union security_ace_object_ctr object;/* [switch_is(type)] */ + struct dom_sid trustee; +}/* [gensize,public,nosize] */; + +enum security_acl_revision { + SECURITY_ACL_REVISION_NT4=2, + SECURITY_ACL_REVISION_ADS=4 +}; + +struct security_acl { + enum security_acl_revision revision; + uint16_t size;/* [value(ndr_size_security_acl(r,ndr->flags))] */ + uint32_t num_aces;/* [range(0 1000)] */ + struct security_ace *aces; +}/* [gensize,public,nosize] */; + +enum security_descriptor_revision { + SECURITY_DESCRIPTOR_REVISION_1=1 +}; + +/* bitmap security_descriptor_type */ +#define SEC_DESC_OWNER_DEFAULTED ( 0x0001 ) +#define SEC_DESC_GROUP_DEFAULTED ( 0x0002 ) +#define SEC_DESC_DACL_PRESENT ( 0x0004 ) +#define SEC_DESC_DACL_DEFAULTED ( 0x0008 ) +#define SEC_DESC_SACL_PRESENT ( 0x0010 ) +#define SEC_DESC_SACL_DEFAULTED ( 0x0020 ) +#define SEC_DESC_DACL_TRUSTED ( 0x0040 ) +#define SEC_DESC_SERVER_SECURITY ( 0x0080 ) +#define SEC_DESC_DACL_AUTO_INHERIT_REQ ( 0x0100 ) +#define SEC_DESC_SACL_AUTO_INHERIT_REQ ( 0x0200 ) +#define SEC_DESC_DACL_AUTO_INHERITED ( 0x0400 ) +#define SEC_DESC_SACL_AUTO_INHERITED ( 0x0800 ) +#define SEC_DESC_DACL_PROTECTED ( 0x1000 ) +#define SEC_DESC_SACL_PROTECTED ( 0x2000 ) +#define SEC_DESC_RM_CONTROL_VALID ( 0x4000 ) +#define SEC_DESC_SELF_RELATIVE ( 0x8000 ) + +struct security_descriptor { + enum security_descriptor_revision revision; + uint16_t type; + struct dom_sid *owner_sid;/* [relative] */ + struct dom_sid *group_sid;/* [relative] */ + struct security_acl *sacl;/* [relative] */ + struct security_acl *dacl;/* [relative] */ +}/* [gensize,public,flag(LIBNDR_FLAG_LITTLE_ENDIAN),nosize] */; + +struct sec_desc_buf { + uint32_t sd_size;/* [value(ndr_size_security_descriptor(sd,ndr->flags)),range(0 0x40000)] */ + struct security_descriptor *sd;/* [unique,subcontext(4)] */ +}/* [public] */; + +struct security_token { + struct dom_sid *user_sid;/* [unique] */ + struct dom_sid *group_sid;/* [unique] */ + uint32_t num_sids; + struct dom_sid **sids;/* [unique,size_is(num_sids)] */ + uint64_t privilege_mask; +}/* [public] */; + +/* bitmap security_secinfo */ +#define SECINFO_OWNER ( 0x00000001 ) +#define SECINFO_GROUP ( 0x00000002 ) +#define SECINFO_DACL ( 0x00000004 ) +#define SECINFO_SACL ( 0x00000008 ) + +#endif /* _HEADER_security */ diff --git a/source3/libndr/sid.c b/source3/libndr/sid.c new file mode 100644 index 0000000000..0bb42a3683 --- /dev/null +++ b/source3/libndr/sid.c @@ -0,0 +1,97 @@ +/* + 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 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. +*/ + +#include "includes.h" + +NTSTATUS ndr_push_dom_sid(struct ndr_push *ndr, int ndr_flags, const struct dom_sid *r) +{ + uint32_t cntr_sub_auths_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num)); + NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths)); + NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) { + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + } + return NT_STATUS_OK; +} + +NTSTATUS ndr_pull_dom_sid(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *r) +{ + uint32_t cntr_sub_auths_0; + TALLOC_CTX *_mem_save_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 > 15) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range"); + } + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + NDR_PULL_ALLOC_N(ndr, r->sub_auths, r->num_auths); + _mem_save_sub_auths_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->sub_auths, 0); + 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])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sub_auths_0, 0); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NT_STATUS_OK; +} + +/* + convert a dom_sid to a string +*/ +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid) +{ + int i, ofs, maxlen; + uint32_t ia; + char *ret; + + if (!sid) { + return talloc_strdup(mem_ctx, "(NULL SID)"); + } + + maxlen = sid->num_auths * 11 + 25; + ret = talloc_size(mem_ctx, maxlen); + if (!ret) return talloc_strdup(mem_ctx, "(SID ERR)"); + + ia = (sid->id_auth[5]) + + (sid->id_auth[4] << 8 ) + + (sid->id_auth[3] << 16) + + (sid->id_auth[2] << 24); + + ofs = snprintf(ret, maxlen, "S-%u-%lu", + (unsigned int)sid->sid_rev_num, (unsigned long)ia); + + for (i = 0; i < sid->num_auths; i++) { + ofs += snprintf(ret + ofs, maxlen - ofs, "-%lu", (unsigned long)sid->sub_auths[i]); + } + + return ret; +} -- cgit