diff options
-rw-r--r-- | source4/libcli/nbt/nbtname.c | 84 | ||||
-rw-r--r-- | source4/librpc/ndr/libndr.h | 1 |
2 files changed, 50 insertions, 35 deletions
diff --git a/source4/libcli/nbt/nbtname.c b/source4/libcli/nbt/nbtname.c index c2fb062025..205567a55b 100644 --- a/source4/libcli/nbt/nbtname.c +++ b/source4/libcli/nbt/nbtname.c @@ -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); } diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h index 328fa7c703..24cb80c994 100644 --- a/source4/librpc/ndr/libndr.h +++ b/source4/librpc/ndr/libndr.h @@ -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; |