1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/librpc/ndr/ndr_nbt.c
Douglas Bagnall cc3a67760c CVE-2020-10745: ndr/dns-utils: prepare for NBT compatibility
NBT has a funny thing where it sometimes needs to send a trailing dot as
part of the last component, because the string representation is a user
name. In DNS, "example.com", and "example.com." are the same, both
having three components ("example", "com", ""); in NBT, we want to treat
them differently, with the second form having the three components
("example", "com.", "").

This retains the logic of e6e2ec0001.

Also DNS compression cannot be turned off for NBT.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
2020-07-02 09:01:41 +00:00

407 lines
15 KiB
C

/*
Unix SMB/CIFS implementation.
CLDAP server structures
Copyright (C) Andrew Tridgell 2005
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* parser auto-generated by pidl, then hand-modified by abartlet */
#include "includes.h"
#include "../libcli/nbt/libnbt.h"
#include "../libcli/netlogon/netlogon.h"
#include "ndr_dns_utils.h"
/* don't allow an unlimited number of name components */
#define MAX_COMPONENTS 128
/**
print a nbt string
*/
_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s)
{
ndr_print_string(ndr, name, s);
}
/*
pull one component of a nbt_string
*/
static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
uint8_t **component,
uint32_t *offset,
uint32_t *max_offset)
{
uint8_t len;
unsigned int loops = 0;
while (loops < 5) {
if (*offset >= ndr->data_size) {
return ndr_pull_error(ndr, NDR_ERR_STRING,
"BAD NBT NAME component");
}
len = ndr->data[*offset];
if (len == 0) {
*offset += 1;
*max_offset = MAX(*max_offset, *offset);
*component = NULL;
return NDR_ERR_SUCCESS;
}
if ((len & 0xC0) == 0xC0) {
/* its a label pointer */
if (1 + *offset >= ndr->data_size) {
return ndr_pull_error(ndr, NDR_ERR_STRING,
"BAD NBT NAME component");
}
*max_offset = MAX(*max_offset, *offset + 2);
*offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
*max_offset = MAX(*max_offset, *offset);
loops++;
continue;
}
if ((len & 0xC0) != 0) {
/* its a reserved length field */
return ndr_pull_error(ndr, NDR_ERR_STRING,
"BAD NBT NAME component");
}
if (*offset + len + 1 > ndr->data_size) {
return ndr_pull_error(ndr, NDR_ERR_STRING,
"BAD NBT NAME component");
}
*component = (uint8_t*)talloc_strndup(
ndr->current_mem_ctx,
(const char *)&ndr->data[1 + *offset], len);
NDR_ERR_HAVE_NO_MEMORY(*component);
*offset += len + 1;
*max_offset = MAX(*max_offset, *offset);
return NDR_ERR_SUCCESS;
}
/* too many pointers */
return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component");
}
/**
pull a nbt_string from the wire
*/
_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
{
uint32_t offset = ndr->offset;
uint32_t max_offset = offset;
unsigned num_components;
char *name;
if (!(ndr_flags & NDR_SCALARS)) {
return NDR_ERR_SUCCESS;
}
name = NULL;
/* break up name into a list of components */
for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
uint8_t *component = NULL;
NDR_CHECK(ndr_pull_component(ndr, &component, &offset, &max_offset));
if (component == NULL) break;
if (name) {
name = talloc_asprintf_append_buffer(name, ".%s", component);
NDR_ERR_HAVE_NO_MEMORY(name);
} else {
name = (char *)component;
}
}
if (num_components == MAX_COMPONENTS) {
return ndr_pull_error(ndr, NDR_ERR_STRING,
"BAD NBT NAME too many components");
}
if (num_components == 0) {
name = talloc_strdup(ndr->current_mem_ctx, "");
NDR_ERR_HAVE_NO_MEMORY(name);
}
(*s) = name;
ndr->offset = max_offset;
return NDR_ERR_SUCCESS;
}
/**
push a nbt string to the wire
*/
_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s)
{
return ndr_push_dns_string_list(ndr,
&ndr->dns_string_list,
ndr_flags,
s,
true);
}
/* Manually modified to handle the dom_sid being optional based on if it is present or all zero */
enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_REQUEST(struct ndr_push *ndr, int ndr_flags, const struct NETLOGON_SAM_LOGON_REQUEST *r)
{
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_push_align(ndr, 4));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->request_count));
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
ndr->flags = _flags_save_string;
}
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
ndr->flags = _flags_save_string;
}
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
ndr->flags = _flags_save_string;
}
NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acct_control));
NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid0(&r->sid, ndr->flags)));
if (ndr_size_dom_sid0(&r->sid, ndr->flags)) {
struct ndr_push *_ndr_sid;
uint32_t _flags_save_DATA_BLOB = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
ndr->flags = _flags_save_DATA_BLOB;
NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
NDR_CHECK(ndr_push_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
}
NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
}
if (ndr_flags & NDR_BUFFERS) {
}
return NDR_ERR_SUCCESS;
}
/* Manually modified to handle the dom_sid being optional based on if it is present (size is non-zero) or not */
enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_REQUEST(struct ndr_pull *ndr, int ndr_flags, struct NETLOGON_SAM_LOGON_REQUEST *r)
{
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_pull_align(ndr, 4));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->request_count));
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
ndr->flags = _flags_save_string;
}
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
ndr->flags = _flags_save_string;
}
{
uint32_t _flags_save_string = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
ndr->flags = _flags_save_string;
}
NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acct_control));
NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_size));
if (r->sid_size) {
uint32_t _flags_save_DATA_BLOB = ndr->flags;
struct ndr_pull *_ndr_sid;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
ndr->flags = _flags_save_DATA_BLOB;
NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sid, 0, r->sid_size));
NDR_CHECK(ndr_pull_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sid, 0, r->sid_size));
} else {
ZERO_STRUCT(r->sid);
}
NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
}
if (ndr_flags & NDR_BUFFERS) {
}
return NDR_ERR_SUCCESS;
}
/* Manually modified to only push some parts of the structure if certain flags are set */
enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_push *ndr, int ndr_flags, const struct NETLOGON_SAM_LOGON_RESPONSE_EX *r)
{
{
uint32_t _flags_save_STRUCT = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_push_align(ndr, 4));
NDR_CHECK(ndr_push_netlogon_command(ndr, NDR_SCALARS, r->command));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain_name));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
if (r->nt_version & NETLOGON_NT_VERSION_5EX_WITH_IP) {
NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
{
struct ndr_push *_ndr_sockaddr;
NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
NDR_CHECK(ndr_push_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr));
NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
}
}
if (r->nt_version & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) {
NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->next_closest_site));
}
NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
}
if (ndr_flags & NDR_BUFFERS) {
NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->domain_uuid));
}
ndr->flags = _flags_save_STRUCT;
}
return NDR_ERR_SUCCESS;
}
/* Manually modified to only pull some parts of the structure if certain flags provided */
enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_pull *ndr, int ndr_flags, struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
uint32_t nt_version_flags)
{
{
uint32_t _flags_save_STRUCT = ndr->flags;
ZERO_STRUCTP(r);
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_pull_align(ndr, 4));
NDR_CHECK(ndr_pull_netlogon_command(ndr, NDR_SCALARS, &r->command));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain_name));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
if (nt_version_flags & NETLOGON_NT_VERSION_5EX_WITH_IP) {
NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sockaddr_size));
{
struct ndr_pull *_ndr_sockaddr;
NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sockaddr, 0, r->sockaddr_size));
NDR_CHECK(ndr_pull_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr));
NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sockaddr, 0, r->sockaddr_size));
}
}
if (nt_version_flags & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) {
NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->next_closest_site));
}
NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version));
if (r->nt_version != nt_version_flags) {
return NDR_ERR_VALIDATE;
}
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
}
if (ndr_flags & NDR_BUFFERS) {
NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->domain_uuid));
}
ndr->flags = _flags_save_STRUCT;
}
return NDR_ERR_SUCCESS;
}
_PUBLIC_ enum ndr_err_code ndr_push_netlogon_samlogon_response(struct ndr_push *ndr, int ndr_flags, const struct netlogon_samlogon_response *r)
{
if (r->ntver == NETLOGON_NT_VERSION_1) {
NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40(
ndr, ndr_flags, &r->data.nt4));
} else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
ndr, ndr_flags, &r->data.nt5_ex));
} else if (r->ntver & NETLOGON_NT_VERSION_5) {
NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE(
ndr, ndr_flags, &r->data.nt5));
} else {
return NDR_ERR_BAD_SWITCH;
}
return NDR_ERR_SUCCESS;
}
_PUBLIC_ enum ndr_err_code ndr_pull_netlogon_samlogon_response(struct ndr_pull *ndr, int ndr_flags, struct netlogon_samlogon_response *r)
{
if (ndr->data_size < 8) {
return NDR_ERR_BUFSIZE;
}
/* lmnttoken */
if (SVAL(ndr->data, ndr->data_size - 4) != 0xffff) {
return NDR_ERR_TOKEN;
}
/* lm20token */
if (SVAL(ndr->data, ndr->data_size - 2) != 0xffff) {
return NDR_ERR_TOKEN;
}
r->ntver = IVAL(ndr->data, ndr->data_size - 8);
if (r->ntver == NETLOGON_NT_VERSION_1) {
NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40(
ndr, ndr_flags, &r->data.nt4));
} else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
ndr, ndr_flags, &r->data.nt5_ex, r->ntver));
if (ndr->offset < ndr->data_size) {
return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
"not all bytes consumed ofs[%u] size[%u]",
ndr->offset, ndr->data_size);
}
} else if (r->ntver & NETLOGON_NT_VERSION_5) {
NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE(
ndr, ndr_flags, &r->data.nt5));
} else {
return NDR_ERR_BAD_SWITCH;
}
return NDR_ERR_SUCCESS;
}
_PUBLIC_ void ndr_print_netlogon_samlogon_response(struct ndr_print *ndr, const char *name, struct netlogon_samlogon_response *r)
{
ndr_print_struct(ndr, name, "netlogon_samlogon_response");
if (r == NULL) { ndr_print_null(ndr); return; }
if (r->ntver == NETLOGON_NT_VERSION_1) {
ndr_print_NETLOGON_SAM_LOGON_RESPONSE_NT40(ndr, "data.nt4", &r->data.nt4);
} else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
ndr_print_NETLOGON_SAM_LOGON_RESPONSE_EX(ndr, "data.nt5_ex", &r->data.nt5_ex);
} else if (r->ntver & NETLOGON_NT_VERSION_5) {
ndr_print_NETLOGON_SAM_LOGON_RESPONSE(ndr, "data.nt5", &r->data.nt5);
}
}