diff options
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); |