r8212: fix pushing of nbt_string's:
authorStefan Metzmacher <metze@samba.org>
Thu, 7 Jul 2005 19:49:35 +0000 (19:49 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:19:20 +0000 (13:19 -0500)
- we now use an ndr_token_list, for the nbt string label pointer offsets
  this avoids to scan the whole buffer

- we need to check for already send string on a per component basis
  not only for the fullname

e.g.
w2k3 response this in the CLDAP netlogon replies

forest: w2k3.vmnet1.vm.base
dns_name: sub1.
pdc_dns_name: w2k3-104.

and this will be interpreted like

forest: w2k3.vmnet1.vm.base
dns_name: sub1.w2k3.vmnet1.vm.base
pdc_dns_name: w2k3-104.w2k3.vmnet1.vm.base

metze

source/libcli/nbt/nbtname.c
source/librpc/ndr/libndr.h

index c2fb062025369cc4407c22e7fadcb6081cb28f0c..205567a55bdf79e76a87b4d4d89ab68d5eb61433 100644 (file)
@@ -136,53 +136,67 @@ NTSTATUS ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s
 */
 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;
        }
 
-       if (s == NULL || *s == 0) {
-               return ndr_push_bytes(ndr, "", 1);
-       }
+       while (s && *s) {
+               NTSTATUS status;
+               char *compname;
+               size_t complen;
+               uint32_t offset;
+
+               /* see if we have pushed the remaing string allready,
+                * if so we use a label pointer to this string
+                */
+               status = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, False);
+               if (NT_STATUS_IS_OK(status)) {
+                       uint8_t b[2];
+                       
+                       if (offset > 0x3FFF) {
+                               return ndr_push_error(ndr, NDR_ERR_STRING,
+                                                     "offset for nbt string label pointer %u[%08X] > 0x00003FFF",
+                                                     offset, offset);
+                       }
 
+                       b[0] = 0xC0 | (offset>>8);
+                       b[1] = (offset & 0xFF);
 
-       fullname = talloc_strdup(ndr, "");
-       NT_STATUS_HAVE_NO_MEMORY(fullname);
+                       return ndr_push_bytes(ndr, b, 2);
+               }
 
-       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++;
-       }
+               complen = strcspn(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) {
-                       uint8_t b[2];
-                       talloc_free(fullname);
-                       b[0] = 0xC0 | (i>>8);
-                       b[1] = (i&0xFF);
-                       return ndr_push_bytes(ndr, b, 2);
+               /* we need to make sure the length fits into 6 bytes */
+               if (complen >= 0x3F) {
+                       return ndr_push_error(ndr, NDR_ERR_STRING,
+                                             "component length %u[%08X] > 0x00003F",
+                                             complen, complen);
                }
-       }
 
-       NDR_CHECK(ndr_push_bytes(ndr, fullname, fulllen));
+               compname = talloc_asprintf(ndr, "%c%*.*s",
+                                               (unsigned char)complen,
+                                               (unsigned char)complen,
+                                               (unsigned char)complen, s);
+               NT_STATUS_HAVE_NO_MEMORY(compname);
 
-       talloc_free(fullname);
+               /* remember the current componemt + the rest of the string
+                * so it can be reused later
+                */
+               NDR_CHECK(ndr_token_store(ndr, &ndr->nbt_string_list, s, ndr->offset));
 
-       return NT_STATUS_OK;
+               /* push just this component into the blob */
+               NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1));
+               talloc_free(compname);
+
+               s += complen;
+               if (*s == '.') s++;
+       }
+
+       /* if we reach the end of the string and have pushed the last component
+        * without using a label pointer, we need to terminate the string
+        */
+       return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
 }
 
 
index 328fa7c703f379293bf87349d3efb7f865635555..24cb80c994ddc2cc70a5f84404032bca20cb046b 100644 (file)
@@ -77,6 +77,7 @@ struct ndr_push {
 
        struct ndr_token_list *switch_list;
        struct ndr_token_list *relative_list;
+       struct ndr_token_list *nbt_string_list;
 
        /* this is used to ensure we generate unique reference IDs */
        uint32_t ptr_count;