r6331: added IDL and test suite for the ADS style response to a datagram netlogon...
authorAndrew Tridgell <tridge@samba.org>
Thu, 14 Apr 2005 02:36:30 +0000 (02:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:11:32 +0000 (13:11 -0500)
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)

source4/build/pidl/typelist.pm
source4/libcli/nbt/nbtname.c
source4/librpc/idl/nbt.idl
source4/torture/nbt/dgram.c

index 432497f9f6b8b39557ce9668bd1d58b64d4130d9..af37a1b8dbad8980ff15e695f85025ac21114bc2 100644 (file)
@@ -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
index 12b8884e2d5c98bcaf0262a032cb528ccf99d783..f7d19d11cfd336ce918a84b1c6034f2729969839 100644 (file)
 #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];
-
-       /* 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;
 }
 
 
index f6c491fe90ab264d3b8de92795638f5902f8d91b..a28c029b7d03d00ca47ef3b1cee81c70903fce12 100644 (file)
@@ -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;
        /*******************************************/
        /* \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 */
                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;
                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;
 
        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 {
index 14d98fc0c0493e4bbbe59c3af5ae7f66010ccb7b..b1dd92621c7882c832ad916b52c4b7a538dc555d 100644 (file)
@@ -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);