mirror of
https://github.com/samba-team/samba.git
synced 2025-11-06 08:23:50 +03:00
r6331: added IDL and test suite for the ADS style response to a datagram netlogon query.
Note that this response is almost identical to the CLDAP netlogon response, so adding that will now be quite easy.
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
30d0c9fb2e
commit
1ea4ed4ad1
@@ -104,7 +104,8 @@ my %scalar_type_mappings =
|
||||
"hyper" => "uint64_t",
|
||||
"NTTIME_1sec" => "NTTIME",
|
||||
"NTTIME_hyper" => "NTTIME",
|
||||
"ipv4address" => "const char *"
|
||||
"ipv4address" => "const char *",
|
||||
"nbt_string" => "const char *"
|
||||
);
|
||||
|
||||
# map from a IDL type to a C header type
|
||||
|
||||
@@ -32,7 +32,15 @@
|
||||
#define MAX_COMPONENTS 10
|
||||
|
||||
/*
|
||||
pull one component of a compressed name
|
||||
print a nbt string
|
||||
*/
|
||||
void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s)
|
||||
{
|
||||
return ndr_print_string(ndr, name, s);
|
||||
}
|
||||
|
||||
/*
|
||||
pull one component of a nbt_string
|
||||
*/
|
||||
static NTSTATUS ndr_pull_component(struct ndr_pull *ndr, uint8_t **component,
|
||||
uint32_t *offset, uint32_t *max_offset)
|
||||
@@ -79,6 +87,97 @@ static NTSTATUS ndr_pull_component(struct ndr_pull *ndr, uint8_t **component,
|
||||
return NT_STATUS_BAD_NETWORK_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
pull a nbt_string from the wire
|
||||
*/
|
||||
NTSTATUS ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint32_t offset = ndr->offset;
|
||||
uint32_t max_offset = offset;
|
||||
unsigned num_components;
|
||||
char *name;
|
||||
|
||||
if (!(ndr_flags & NDR_SCALARS)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
|
||||
/* break up name into a list of components */
|
||||
for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
|
||||
uint8_t *component;
|
||||
status = ndr_pull_component(ndr, &component, &offset, &max_offset);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
if (component == NULL) break;
|
||||
if (name) {
|
||||
name = talloc_asprintf_append(name, ".%s", component);
|
||||
NT_STATUS_HAVE_NO_MEMORY(name);
|
||||
} else {
|
||||
name = component;
|
||||
}
|
||||
}
|
||||
if (num_components == MAX_COMPONENTS) {
|
||||
return NT_STATUS_BAD_NETWORK_NAME;
|
||||
}
|
||||
if (num_components == 0) {
|
||||
name = talloc_strdup(ndr, "");
|
||||
NT_STATUS_HAVE_NO_MEMORY(name);
|
||||
}
|
||||
|
||||
(*s) = name;
|
||||
ndr->offset = max_offset;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
push a nbt string to the wire
|
||||
*/
|
||||
NTSTATUS ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s)
|
||||
{
|
||||
int i;
|
||||
int fulllen;
|
||||
char *fullname;
|
||||
|
||||
if (!(ndr_flags & NDR_SCALARS)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
fullname = talloc_strdup(ndr, "");
|
||||
NT_STATUS_HAVE_NO_MEMORY(fullname);
|
||||
|
||||
while (*s) {
|
||||
int len = strcspn(s, ".");
|
||||
fullname = talloc_asprintf_append(fullname, "%c%*.*s",
|
||||
(unsigned char)len,
|
||||
(unsigned char)len,
|
||||
(unsigned char)len, s);
|
||||
NT_STATUS_HAVE_NO_MEMORY(fullname);
|
||||
s += len;
|
||||
if (*s == '.') s++;
|
||||
}
|
||||
|
||||
/* see if we can find the fullname in the existing packet - if
|
||||
so, we can use a NBT name pointer. This allows us to fit
|
||||
longer names into the packet */
|
||||
fulllen = strlen(fullname)+1;
|
||||
for (i=0;i + fulllen < ndr->offset;i++) {
|
||||
if (ndr->data[i] == fullname[0] &&
|
||||
memcmp(fullname, &ndr->data[i], fulllen) == 0) {
|
||||
talloc_free(fullname);
|
||||
return ndr_push_uint16(ndr, NDR_SCALARS, 0xC000 | i);
|
||||
}
|
||||
}
|
||||
|
||||
NDR_CHECK(ndr_push_bytes(ndr, fullname, fulllen));
|
||||
|
||||
talloc_free(fullname);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
decompress a 'compressed' name component
|
||||
*/
|
||||
@@ -151,57 +250,49 @@ static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
|
||||
return cname;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
pull a nbt name from the wire
|
||||
*/
|
||||
NTSTATUS ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint_t num_components;
|
||||
uint32_t offset = ndr->offset;
|
||||
uint32_t max_offset = offset;
|
||||
uint8_t *components[MAX_COMPONENTS];
|
||||
int i;
|
||||
uint8_t *scope;
|
||||
char *cname;
|
||||
const char *s;
|
||||
|
||||
if (!(ndr_flags & NDR_SCALARS)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/* break up name into a list of components */
|
||||
for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
|
||||
status = ndr_pull_component(ndr, &components[num_components],
|
||||
&offset, &max_offset);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
if (components[num_components] == NULL) break;
|
||||
}
|
||||
if (num_components == MAX_COMPONENTS ||
|
||||
num_components == 0) {
|
||||
return NT_STATUS_BAD_NETWORK_NAME;
|
||||
status = ndr_pull_nbt_string(ndr, ndr_flags, &s);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
scope = strchr(s, '.');
|
||||
if (scope) {
|
||||
*scope = 0;
|
||||
r->scope = talloc_strdup(ndr, scope+1);
|
||||
NT_STATUS_HAVE_NO_MEMORY(r->scope);
|
||||
} else {
|
||||
r->scope = NULL;
|
||||
}
|
||||
|
||||
ndr->offset = max_offset;
|
||||
cname = discard_const_p(char, s);
|
||||
|
||||
/* the first component is limited to 16 bytes in the DOS charset,
|
||||
which is 32 in the 'compressed' form */
|
||||
if (strlen(components[0]) > 32) {
|
||||
if (strlen(cname) > 32) {
|
||||
return NT_STATUS_BAD_NETWORK_NAME;
|
||||
}
|
||||
|
||||
/* decompress the first component */
|
||||
status = decompress_name(components[0], &r->type);
|
||||
status = decompress_name(cname, &r->type);
|
||||
NT_STATUS_NOT_OK_RETURN(status);
|
||||
|
||||
r->name = components[0];
|
||||
r->name = talloc_strdup(ndr, cname);
|
||||
NT_STATUS_HAVE_NO_MEMORY(r->name);
|
||||
|
||||
/* combine the remaining components into the scope */
|
||||
scope = components[1];
|
||||
for (i=2;i<num_components;i++) {
|
||||
scope = talloc_asprintf_append(scope, ".%s", components[i]);
|
||||
NT_STATUS_HAVE_NO_MEMORY(scope);
|
||||
}
|
||||
|
||||
r->scope = scope;
|
||||
talloc_free(cname);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -211,69 +302,28 @@ NTSTATUS ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name
|
||||
*/
|
||||
NTSTATUS ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, struct nbt_name *r)
|
||||
{
|
||||
uint_t num_components;
|
||||
uint8_t *components[MAX_COMPONENTS];
|
||||
char *dscope=NULL, *p;
|
||||
uint8_t *cname, *fullname;
|
||||
int i;
|
||||
int fulllen;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!(ndr_flags & NDR_SCALARS)) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
if (r->scope) {
|
||||
dscope = talloc_strdup(ndr, r->scope);
|
||||
NT_STATUS_HAVE_NO_MEMORY(dscope);
|
||||
}
|
||||
|
||||
cname = compress_name(ndr, r->name, r->type);
|
||||
NT_STATUS_HAVE_NO_MEMORY(cname);
|
||||
|
||||
/* form the base components */
|
||||
components[0] = cname;
|
||||
num_components = 1;
|
||||
|
||||
while (dscope && (p=strchr(dscope, '.')) &&
|
||||
num_components < MAX_COMPONENTS) {
|
||||
*p = 0;
|
||||
components[num_components] = dscope;
|
||||
dscope = p+1;
|
||||
num_components++;
|
||||
}
|
||||
if (dscope && num_components < MAX_COMPONENTS) {
|
||||
components[num_components++] = dscope;
|
||||
}
|
||||
if (num_components == MAX_COMPONENTS) {
|
||||
return NT_STATUS_BAD_NETWORK_NAME;
|
||||
}
|
||||
|
||||
fullname = talloc_asprintf(ndr, "%c%s", (unsigned char)strlen(cname), cname);
|
||||
NT_STATUS_HAVE_NO_MEMORY(fullname);
|
||||
|
||||
for (i=1;i<num_components;i++) {
|
||||
fullname = talloc_asprintf_append(fullname, "%c%s",
|
||||
(unsigned char)strlen(components[i]), components[i]);
|
||||
if (r->scope) {
|
||||
fullname = talloc_asprintf(ndr, "%s.%s", cname, r->scope);
|
||||
NT_STATUS_HAVE_NO_MEMORY(fullname);
|
||||
talloc_free(cname);
|
||||
} else {
|
||||
fullname = cname;
|
||||
}
|
||||
|
||||
/* see if we can find the fullname in the existing packet - if
|
||||
so, we can use a NBT name pointer. This allows us to fit
|
||||
longer names into the packet */
|
||||
fulllen = strlen(fullname)+1;
|
||||
for (i=0;i + fulllen < ndr->offset;i++) {
|
||||
if (ndr->data[i] == fullname[0] &&
|
||||
memcmp(fullname, &ndr->data[i], fulllen) == 0) {
|
||||
talloc_free(fullname);
|
||||
return ndr_push_uint16(ndr, NDR_SCALARS, 0xC000 | i);
|
||||
}
|
||||
}
|
||||
|
||||
NDR_CHECK(ndr_push_bytes(ndr, fullname, fulllen));
|
||||
|
||||
status = ndr_push_nbt_string(ndr, ndr_flags, fullname);
|
||||
talloc_free(fullname);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
} nbt_name_type;
|
||||
|
||||
/* the ndr parser for nbt_name is separately defined in
|
||||
nbtname.c */
|
||||
nbtname.c (along with the parsers for nbt_string) */
|
||||
typedef [nopull,nopush] struct {
|
||||
string name;
|
||||
string scope;
|
||||
@@ -330,9 +330,11 @@
|
||||
/*******************************************/
|
||||
/* \MAILSLOT\NET\NETLOGON mailslot requests */
|
||||
typedef enum {
|
||||
NETLOGON_QUERY_FOR_PDC = 0x7,
|
||||
NETLOGON_ANNOUNCE_UAS = 0xa,
|
||||
NETLOGON_RESPONSE_FROM_PDC = 0xc
|
||||
NETLOGON_QUERY_FOR_PDC = 0x7,
|
||||
NETLOGON_ANNOUNCE_UAS = 0xa,
|
||||
NETLOGON_RESPONSE_FROM_PDC = 0xc,
|
||||
NETLOGON_QUERY_FOR_PDC2 = 0x12,
|
||||
NETLOGON_RESPONSE_FROM_PDC2 = 0x17
|
||||
} nbt_netlogon_command;
|
||||
|
||||
/* query for pdc request */
|
||||
@@ -346,7 +348,19 @@
|
||||
uint16 lm20_token;
|
||||
} nbt_netlogon_query_for_pdc;
|
||||
|
||||
/* response from request */
|
||||
/* query for pdc request - new style */
|
||||
typedef struct {
|
||||
uint16 request_count;
|
||||
nstring computer_name;
|
||||
nstring user_name;
|
||||
astring mailslot_name;
|
||||
uint32 unknown[2];
|
||||
uint32 nt_version;
|
||||
uint16 lmnt_token;
|
||||
uint16 lm20_token;
|
||||
} nbt_netlogon_query_for_pdc2;
|
||||
|
||||
/* response from pdc */
|
||||
typedef struct {
|
||||
astring pdc_name;
|
||||
[flag(NDR_ALIGN2)] DATA_BLOB _pad;
|
||||
@@ -357,6 +371,29 @@
|
||||
uint16 lm20_token;
|
||||
} nbt_netlogon_response_from_pdc;
|
||||
|
||||
/* response from pdc - type2 */
|
||||
typedef struct {
|
||||
[flag(NDR_ALIGN4)] DATA_BLOB _pad;
|
||||
uint32 server_type;
|
||||
GUID domain_uuid;
|
||||
nbt_string forest;
|
||||
nbt_string dns_domain;
|
||||
nbt_string pdc_dns_name;
|
||||
astring domain;
|
||||
nbt_string pdc_name;
|
||||
nbt_string user_name;
|
||||
nbt_string site_name;
|
||||
nbt_string site_name2;
|
||||
uint8 unknown;
|
||||
uint32 unknown2;
|
||||
[flag(NDR_BIG_ENDIAN)]
|
||||
ipv4address pdc_ip;
|
||||
uint32 unknown3[2];
|
||||
uint32 nt_version;
|
||||
uint16 lmnt_token;
|
||||
uint16 lm20_token;
|
||||
} nbt_netlogon_response_from_pdc2;
|
||||
|
||||
/* announce change to UAS or SAM */
|
||||
typedef struct {
|
||||
uint32 db_index;
|
||||
@@ -387,8 +424,10 @@
|
||||
|
||||
typedef [nodiscriminant] union {
|
||||
[case(NETLOGON_QUERY_FOR_PDC)] nbt_netlogon_query_for_pdc pdc;
|
||||
[case(NETLOGON_QUERY_FOR_PDC2)] nbt_netlogon_query_for_pdc2 pdc2;
|
||||
[case(NETLOGON_ANNOUNCE_UAS)] nbt_netlogon_announce_uas uas;
|
||||
[case(NETLOGON_RESPONSE_FROM_PDC)] nbt_netlogon_response_from_pdc response;
|
||||
[case(NETLOGON_RESPONSE_FROM_PDC2)] nbt_netlogon_response_from_pdc2 response2;
|
||||
} nbt_netlogon_request;
|
||||
|
||||
typedef [flag(NDR_NOALIGN),public] struct {
|
||||
|
||||
@@ -117,6 +117,68 @@ failed:
|
||||
}
|
||||
|
||||
|
||||
/* test UDP/138 netlogon requests */
|
||||
static BOOL nbt_test_netlogon2(TALLOC_CTX *mem_ctx,
|
||||
struct nbt_name name, const char *address)
|
||||
{
|
||||
struct dgram_mailslot_handler *dgmslot;
|
||||
struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(mem_ctx, NULL);
|
||||
const char *myaddress = talloc_strdup(dgmsock, iface_best_ip(address));
|
||||
struct nbt_netlogon_packet logon;
|
||||
struct nbt_name myname;
|
||||
NTSTATUS status;
|
||||
struct timeval tv = timeval_current();
|
||||
int replies = 0;
|
||||
|
||||
/* try receiving replies on port 138 first, which will only
|
||||
work if we are root and smbd/nmbd are not running - fall
|
||||
back to listening on any port, which means replies from
|
||||
some windows versions won't be seen */
|
||||
status = socket_listen(dgmsock->sock, myaddress, lp_dgram_port(), 0, 0);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
socket_listen(dgmsock->sock, myaddress, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* setup a temporary mailslot listener for replies */
|
||||
dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
|
||||
netlogon_handler, &replies);
|
||||
|
||||
|
||||
ZERO_STRUCT(logon);
|
||||
logon.command = NETLOGON_QUERY_FOR_PDC2;
|
||||
logon.req.pdc2.request_count = 0;
|
||||
logon.req.pdc2.computer_name = TEST_NAME;
|
||||
logon.req.pdc2.user_name = "";
|
||||
logon.req.pdc2.mailslot_name = dgmslot->mailslot_name;
|
||||
logon.req.pdc2.nt_version = 11;
|
||||
logon.req.pdc2.lmnt_token = 0xFFFF;
|
||||
logon.req.pdc2.lm20_token = 0xFFFF;
|
||||
|
||||
myname.name = TEST_NAME;
|
||||
myname.type = NBT_NAME_CLIENT;
|
||||
myname.scope = NULL;
|
||||
|
||||
status = dgram_mailslot_netlogon_send(dgmsock, &name, address,
|
||||
0, &myname, &logon);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
printf("Failed to send netlogon request - %s\n", nt_errstr(status));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
while (timeval_elapsed(&tv) < 5 && replies == 0) {
|
||||
event_loop_once(dgmsock->event_ctx);
|
||||
}
|
||||
|
||||
talloc_free(dgmsock);
|
||||
return True;
|
||||
|
||||
failed:
|
||||
talloc_free(dgmsock);
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
reply handler for ntlogon request
|
||||
*/
|
||||
@@ -248,6 +310,7 @@ BOOL torture_nbt_dgram(void)
|
||||
}
|
||||
|
||||
ret &= nbt_test_netlogon(mem_ctx, name, address);
|
||||
ret &= nbt_test_netlogon2(mem_ctx, name, address);
|
||||
ret &= nbt_test_ntlogon(mem_ctx, name, address);
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
Reference in New Issue
Block a user