Exemplo n.º 1
0
/**
  pull a UCS2 string from a request packet, returning a talloced unix string

  the string length is limited by the 3 things:
   - the data size in the request (end of packet)
   - the passed 'byte_len' if it is not -1
   - the end of string (null termination)

  Note that 'byte_len' is the number of bytes in the packet

  on failure zero is returned and *dest is set to NULL, otherwise the number
  of bytes consumed in the packet is returned
*/
static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, unsigned int flags)
{
	int src_len, src_len2, alignment=0;
	bool ret;
	char *dest2;
	size_t converted_size = 0;

	if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
		src++;
		alignment=1;
		if (byte_len != -1) {
			byte_len--;
		}
	}

	if (flags & STR_NO_RANGE_CHECK) {
		src_len = byte_len;
	} else {
		src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
		if (byte_len != -1 && src_len > byte_len) {
			src_len = byte_len;
		}
	}

	if (src_len < 0) {
		*dest = NULL;
		return 0;
	}
	
	src_len2 = utf16_len_n(src, src_len);
	if (src_len2 == 0) {
		*dest = talloc_strdup(bufinfo->mem_ctx, "");
		return src_len2 + alignment;
	}

	ret = convert_string_talloc(bufinfo->mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &converted_size);

	if (!ret) {
		*dest = NULL;
		return 0;
	}
	*dest = dest2;

	return src_len2 + alignment;
}
Exemplo n.º 2
0
/**
  pull a UCS2 string from a blob, returning a talloced unix string

  the string length is limited by the 3 things:
   - the data size in the blob
   - the passed 'byte_len' if it is not -1
   - the end of string (null termination)

  Note that 'byte_len' is the number of bytes in the packet

  on failure zero is returned and *dest is set to NULL, otherwise the number
  of bytes consumed in the blob is returned
*/
size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
			     const DATA_BLOB *blob, const char **dest, 
			     const uint8_t *src, int byte_len, unsigned int flags)
{
	int src_len, src_len2, alignment=0;
	size_t ret_size;
	bool ret;
	char *dest2;

	if (src < blob->data ||
	    src >= (blob->data + blob->length)) {
		*dest = NULL;
		return 0;
	}

	src_len = blob->length - PTR_DIFF(src, blob->data);

	if (byte_len != -1 && src_len > byte_len) {
		src_len = byte_len;
	}

	if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
		src++;
		alignment=1;
		src_len--;
	}

	if (src_len < 2) {
		*dest = NULL;
		return 0;
	}

	src_len2 = utf16_len_n(src, src_len);

	ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
	if (!ret) {
		*dest = NULL;
		return 0;
	}
	*dest = dest2;

	return src_len2 + alignment;
}
Exemplo n.º 3
0
/*
  pull a UCS2 string from a request packet, returning a talloced unix string

  the string length is limited by the 3 things:
   - the data size in the request (end of packet)
   - the passed 'byte_len' if it is not -1
   - the end of string (null termination)

  Note that 'byte_len' is the number of bytes in the packet

  on failure zero is returned and *dest is set to NULL, otherwise the number
  of bytes consumed in the packet is returned
*/
static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
				char **dest, const uint8_t *src, int byte_len, unsigned int flags)
{
	int src_len, src_len2, alignment=0;
	bool ret;
	size_t ret_size;

	if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
		src++;
		alignment=1;
		if (byte_len != -1) {
			byte_len--;
		}
	}

	src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
	if (src_len < 0) {
		*dest = NULL;
		return 0;
	}
	if (byte_len != -1 && src_len > byte_len) {
		src_len = byte_len;
	}

	src_len2 = utf16_len_n(src, src_len);

	/* ucs2 strings must be at least 2 bytes long */
	if (src_len2 < 2) {
		*dest = NULL;
		return 0;
	}

	ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
	if (!ret) {
		*dest = NULL;
		return 0;
	}

	return src_len2 + alignment;
}
Exemplo n.º 4
0
/**
  pull a general string from the wire
*/
NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
{
	char *as=NULL;
	uint32_t len1, ofs, len2;
	uint16_t len3;
	int ret;
	charset_t chset = CH_UTF16LE;
	unsigned byte_mul = 2;
	unsigned flags = ndr->flags;
	unsigned c_len_term = 0;

	if (!(ndr_flags & NDR_SCALARS)) {
		return NT_STATUS_OK;
	}

	if (NDR_BE(ndr)) {
		chset = CH_UTF16BE;
	}

	if (flags & LIBNDR_FLAG_STR_ASCII) {
		chset = CH_DOS;
		byte_mul = 1;
		flags &= ~LIBNDR_FLAG_STR_ASCII;
	}

	if (flags & LIBNDR_FLAG_STR_UTF8) {
		chset = CH_UTF8;
		byte_mul = 1;
		flags &= ~LIBNDR_FLAG_STR_UTF8;
	}

	flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
	if (flags & LIBNDR_FLAG_STR_CHARLEN) {
		c_len_term = 1;
		flags &= ~LIBNDR_FLAG_STR_CHARLEN;
	}

	switch (flags & LIBNDR_STRING_FLAGS) {
	case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
	case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
		if (ofs != 0) {
			return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
					      ndr->flags & LIBNDR_STRING_FLAGS);
		}
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
		if (len2 > len1) {
			return ndr_pull_error(ndr, NDR_ERR_STRING, 
					      "Bad string lengths len1=%u ofs=%u len2=%u\n", 
					      len1, ofs, len2);
		}
		NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul);
		if (len2 == 0) {
			as = talloc_strdup(ndr->current_mem_ctx, "");
		} else {
			ret = convert_string_talloc(ndr->current_mem_ctx,
						    chset, CH_UNIX, 
						    ndr->data+ndr->offset, 
						    (len2 + c_len_term)*byte_mul,
						    &as, True);
			if (ret == -1) {
				return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
						      "Bad character conversion");
			}
		}
		NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul));

		if (len1 != len2) {
			DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as));
		}

		/* this is a way of detecting if a string is sent with the wrong
		   termination */
		if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
			if (strlen(as) < (len2 + c_len_term)) {
				DEBUG(6,("short string '%s'\n", as));
			}
		} else {
			if (strlen(as) == (len2 + c_len_term)) {
				DEBUG(6,("long string '%s'\n", as));
			}
		}
		*s = as;
		break;

	case LIBNDR_FLAG_STR_SIZE4:
	case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
		NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
		if (len1 == 0) {
			as = talloc_strdup(ndr->current_mem_ctx, "");
		} else {
			ret = convert_string_talloc(ndr->current_mem_ctx,
						    chset, CH_UNIX, 
						    ndr->data+ndr->offset, 
						    (len1 + c_len_term)*byte_mul,
						    &as, False);
			if (ret == -1) {
				return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
						      "Bad character conversion");
			}
		}
		NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));

		/* this is a way of detecting if a string is sent with the wrong
		   termination */
		if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
			if (strlen(as) < (len1 + c_len_term)) {
				DEBUG(6,("short string '%s'\n", as));
			}
		} else {
			if (strlen(as) == (len1 + c_len_term)) {
				DEBUG(6,("long string '%s'\n", as));
			}
		}
		*s = as;
		break;

	case LIBNDR_FLAG_STR_LEN4:
	case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
		if (ofs != 0) {
			return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n",
					      ndr->flags & LIBNDR_STRING_FLAGS);
		}
		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
		NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul);
		if (len1 == 0) {
			as = talloc_strdup(ndr->current_mem_ctx, "");
		} else {
			ret = convert_string_talloc(ndr->current_mem_ctx,
						    chset, CH_UNIX, 
						    ndr->data+ndr->offset, 
						    (len1 + c_len_term)*byte_mul,
						    &as, False);
			if (ret == -1) {
				return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
						      "Bad character conversion");
			}
		}
		NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul));

		/* this is a way of detecting if a string is sent with the wrong
		   termination */
		if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
			if (strlen(as) < (len1 + c_len_term)) {
				DEBUG(6,("short string '%s'\n", as));
			}
		} else {
			if (strlen(as) == (len1 + c_len_term)) {
				DEBUG(6,("long string '%s'\n", as));
			}
		}
		*s = as;
		break;


	case LIBNDR_FLAG_STR_SIZE2:
	case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
		NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul);
		if (len3 == 0) {
			as = talloc_strdup(ndr->current_mem_ctx, "");
		} else {
			ret = convert_string_talloc(ndr->current_mem_ctx,
						    chset, CH_UNIX, 
						    ndr->data+ndr->offset, 
						    (len3 + c_len_term)*byte_mul,
						    &as, False);
			if (ret == -1) {
				return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
						      "Bad character conversion");
			}
		}
		NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul));

		/* this is a way of detecting if a string is sent with the wrong
		   termination */
		if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
			if (strlen(as) < (len3 + c_len_term)) {
				DEBUG(6,("short string '%s'\n", as));
			}
		} else {
			if (strlen(as) == (len3 + c_len_term)) {
				DEBUG(6,("long string '%s'\n", as));
			}
		}
		*s = as;
		break;

	case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
		NDR_PULL_NEED_BYTES(ndr, len3);
		if (len3 == 0) {
			as = talloc_strdup(ndr->current_mem_ctx, "");
		} else {
			ret = convert_string_talloc(ndr->current_mem_ctx,
						    chset, CH_UNIX, 
						    ndr->data+ndr->offset, 
						    len3, &as, False);
			if (ret == -1) {
				return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
						      "Bad character conversion");
			}
		}
		NDR_CHECK(ndr_pull_advance(ndr, len3));
		*s = as;
		break;

	case LIBNDR_FLAG_STR_NULLTERM:
		if (byte_mul == 1) {
			len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
		} else {
			len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
		}
		ret = convert_string_talloc(ndr->current_mem_ctx,
					    chset, CH_UNIX, 
					    ndr->data+ndr->offset, 
					    len1, &as, False);
		if (ret == -1) {
			return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
					      "Bad character conversion");
		}
		NDR_CHECK(ndr_pull_advance(ndr, len1));
		*s = as;
		break;

	case LIBNDR_FLAG_STR_FIXLEN15:
	case LIBNDR_FLAG_STR_FIXLEN32:
		len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
		NDR_PULL_NEED_BYTES(ndr, len1*byte_mul);
		ret = convert_string_talloc(ndr->current_mem_ctx,
					    chset, CH_UNIX, 
					    ndr->data+ndr->offset, 
					    len1*byte_mul, &as, False);
		if (ret == -1) {
			return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 
					      "Bad character conversion");
		}
		NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul));
		*s = as;
		break;

	default:
		return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
				      ndr->flags & LIBNDR_STRING_FLAGS);
	}

	return NT_STATUS_OK;
}