diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-04-14 02:36:30 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:11:32 -0500 |
commit | 8d0a36366c741d0ae9302f1ac8cc6894033be687 (patch) | |
tree | 34a19b847efc4865c7534a78ca7e862de4401deb /source4 | |
parent | 6f036daaa4a3f8c73512a7549a399e9b0f1f2758 (diff) | |
download | samba-8d0a36366c741d0ae9302f1ac8cc6894033be687.tar.gz samba-8d0a36366c741d0ae9302f1ac8cc6894033be687.tar.bz2 samba-8d0a36366c741d0ae9302f1ac8cc6894033be687.zip |
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 used to be commit 1ea4ed4ad1d9336f8288283688fa2d7bebfa533c)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/build/pidl/typelist.pm | 3 | ||||
-rw-r--r-- | source4/libcli/nbt/nbtname.c | 206 | ||||
-rw-r--r-- | source4/librpc/idl/nbt.idl | 49 | ||||
-rw-r--r-- | source4/torture/nbt/dgram.c | 63 |
4 files changed, 237 insertions, 84 deletions
diff --git a/source4/build/pidl/typelist.pm b/source4/build/pidl/typelist.pm index 432497f9f6..af37a1b8db 100644 --- a/source4/build/pidl/typelist.pm +++ b/source4/build/pidl/typelist.pm @@ -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 diff --git a/source4/libcli/nbt/nbtname.c b/source4/libcli/nbt/nbtname.c index 12b8884e2d..f7d19d11cf 100644 --- a/source4/libcli/nbt/nbtname.c +++ b/source4/libcli/nbt/nbtname.c @@ -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) @@ -80,6 +88,97 @@ static NTSTATUS ndr_pull_component(struct ndr_pull *ndr, uint8_t **component, } /* + 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 */ static NTSTATUS decompress_name(char *name, enum nbt_name_type *type) @@ -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]; - - /* 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->name = talloc_strdup(ndr, cname); + NT_STATUS_HAVE_NO_MEMORY(r->name); - 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; } diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl index f6c491fe90..a28c029b7d 100644 --- a/source4/librpc/idl/nbt.idl +++ b/source4/librpc/idl/nbt.idl @@ -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 { diff --git a/source4/torture/nbt/dgram.c b/source4/torture/nbt/dgram.c index 14d98fc0c0..b1dd92621c 100644 --- a/source4/torture/nbt/dgram.c +++ b/source4/torture/nbt/dgram.c @@ -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); |