*/
#include "includes.h"
+#include "system/iconv.h"
#include "librpc/gen_ndr/ndr_nbt.h"
/* don't allow an unlimited number of name components */
#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)
+{
+ 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)
if (1 + *offset >= ndr->data_size) {
return NT_STATUS_BAD_NETWORK_NAME;
}
+ *max_offset = MAX(*max_offset, *offset + 2);
*offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
- *max_offset = MAX(*max_offset, *offset + 1);
+ *max_offset = MAX(*max_offset, *offset);
loops++;
continue;
}
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)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NT_STATUS_OK;
+ }
+
+ 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);
+
+ return ndr_push_bytes(ndr, b, 2);
+ }
+
+ complen = strcspn(s, ".");
+
+ /* 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",
+ (unsigned)complen, (unsigned)complen);
+ }
+
+ compname = talloc_asprintf(ndr, "%c%*.*s",
+ (unsigned char)complen,
+ (unsigned char)complen,
+ (unsigned char)complen, s);
+ NT_STATUS_HAVE_NO_MEMORY(compname);
+
+ /* 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));
+
+ /* 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);
+}
+
+
/*
decompress a 'compressed' name component
*/
cname[2*i] = 'A' + (name[i]>>4);
cname[1+2*i] = 'A' + (name[i]&0xF);
}
- if (name[0] == '*') {
+ if (strcmp(name, "*") == 0) {
pad_char = 0;
} else {
pad_char = ' ';
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];
+ r->name = talloc_strdup(ndr, cname);
+ NT_STATUS_HAVE_NO_MEMORY(r->name);
- /* 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->scope = scope;
+ talloc_free(cname);
return NT_STATUS_OK;
}
/*
push a nbt name to the wire
*/
-NTSTATUS ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, struct nbt_name *r)
+NTSTATUS ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r)
{
- uint_t num_components;
- uint8_t *components[MAX_COMPONENTS];
- char *dscope=NULL, *p;
- uint8_t *cname;
- int i;
+ uint8_t *cname, *fullname;
+ 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;
- }
-
- /* push the components */
- for (i=0;i<num_components;i++) {
- uint8_t len = strlen(components[i]);
- NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, len));
- NDR_CHECK(ndr_push_bytes(ndr, components[i], len));
+ if (r->scope) {
+ fullname = talloc_asprintf(ndr, "%s.%s", cname, r->scope);
+ NT_STATUS_HAVE_NO_MEMORY(fullname);
+ talloc_free(cname);
+ } else {
+ fullname = cname;
}
- NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0));
-
- return NT_STATUS_OK;
+
+ status = ndr_push_nbt_string(ndr, ndr_flags, fullname);
+#if 0
+ /* this free conflicts with the use of pointers into strings
+ in the ndr_token_store() calls above. Metze, can you look
+ at this? */
+ talloc_free(fullname);
+#endif
+ return status;
}
}
if (strlen(name) > 15) {
const char *p = strchr(name, '.');
+ char *s;
if (p - name > 15) {
n->name = "*SMBSERVER";
return;
}
- n->name = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
+ s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
+ n->name = strupper_talloc(mem_ctx, s);
return;
}
- n->name = talloc_strdup(mem_ctx, name);
+ n->name = strupper_talloc(mem_ctx, name);
}
+
+
+/*
+ escape a string into a form containing only a small set of characters,
+ the rest is hex encoded. This is similar to URL encoding
+*/
+static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
+{
+ int i, len;
+ char *ret;
+ const char *valid_chars = "_-.$@ ";
+#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
+
+ for (len=i=0;s[i];i++,len++) {
+ if (!NBT_CHAR_ALLOW(s[i])) {
+ len += 2;
+ }
+ }
+
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ for (len=i=0;s[i];i++) {
+ if (NBT_CHAR_ALLOW(s[i])) {
+ ret[len++] = s[i];
+ } else {
+ snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
+ len += 3;
+ }
+ }
+ ret[len] = 0;
+
+ return ret;
+}
+
+
+/*
+ form a string for a NBT name
+*/
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ char *ret;
+ if (name->scope) {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type,
+ nbt_hex_encode(tmp_ctx, name->scope));
+ } else {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+