summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/build/pidl/typelist.pm3
-rw-r--r--source4/libcli/nbt/nbtname.c206
-rw-r--r--source4/librpc/idl/nbt.idl49
-rw-r--r--source4/torture/nbt/dgram.c63
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);