Exemplo n.º 1
0
/*
  this is like smbcli_req_append_string but it also return the
  non-terminated string byte length, which can be less than the number
  of bytes consumed in the packet for 2 reasons:

   1) the string in the packet may be null terminated
   2) the string in the packet may need a 1 byte UCS2 alignment

 this is used in places where the non-terminated string byte length is
 placed in the packet as a separate field  
*/
size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len)
{
	int diff = 0;
	size_t ret;

	/* determine string type to use */
	if (!(flags & (STR_ASCII|STR_UNICODE))) {
		flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
	}

	/* see if an alignment byte will be used */
	if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
		diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
	}

	/* do the hard work */
	ret = smbcli_req_append_string(req, str, flags);

	/* see if we need to subtract the termination */
	if (flags & STR_TERMINATE) {
		diff += (flags & STR_UNICODE) ? 2 : 1;
	}

	if (ret >= diff) {
		(*len) = ret - diff;
	} else {
		(*len) = ret;
	}

	return ret;
}
Exemplo n.º 2
0
size_t align_string(const void *base_ptr, const char *p, int flags)
{
	if (!(flags & STR_ASCII) && \
	    ((flags & STR_UNICODE || \
	      (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
		return ucs2_align(base_ptr, p, flags);
	}
	return 0;
}
Exemplo n.º 3
0
size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
{
	size_t len=0;
	size_t src_len;
	size_t ret;

	/* treat a pstring as "unlimited" length */
	if (dest_len == (size_t)-1)
		dest_len = sizeof(pstring);

	if (flags & STR_TERMINATE)
		src_len = (size_t)-1;
	else
		src_len = strlen(src);

	if (ucs2_align(base_ptr, dest, flags)) {
		*(char *)dest = 0;
		dest = (void *)((char *)dest + 1);
		if (dest_len)
			dest_len--;
		len++;
	}

	/* ucs2 is always a multiple of 2 bytes */
	dest_len &= ~1;

	ret =  convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, True);
	if (ret == (size_t)-1) {
		return 0;
	}

	len += ret;

	if (flags & STR_UPPER) {
		smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
		size_t i;

		/* We check for i < (ret / 2) below as the dest string isn't null
		   terminated if STR_TERMINATE isn't set. */

		for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
			smb_ucs2_t v = toupper_w(dest_ucs2[i]);
			if (v != dest_ucs2[i]) {
				dest_ucs2[i] = v;
			}
		}
	}

	return len;
}
Exemplo n.º 4
0
size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
{
	size_t ret;

	if (dest_len == (size_t)-1)
		dest_len = sizeof(pstring);

	if (ucs2_align(base_ptr, src, flags)) {
		src = (const void *)((const char *)src + 1);
		if (src_len != (size_t)-1)
			src_len--;
	}

	if (flags & STR_TERMINATE) {
		/* src_len -1 is the default for null terminated strings. */
		if (src_len != (size_t)-1) {
			size_t len = strnlen_w((const smb_ucs2_t *)src,
						src_len/2);
			if (len < src_len/2)
				len++;
			src_len = len*2;
		}
	}

	/* ucs2 is always a multiple of 2 bytes */
	if (src_len != (size_t)-1)
		src_len &= ~1;
	
	ret = convert_string(CH_UTF16LE, CH_UNIX, src, src_len, dest, dest_len, True);
	if (ret == (size_t)-1) {
		return 0;
	}

	if (src_len == (size_t)-1)
		src_len = ret*2;
		
	if (dest_len && ret) {
		/* Did we already process the terminating zero ? */
		if (dest[MIN(ret-1, dest_len-1)] != 0) {
			dest[MIN(ret, dest_len-1)] = 0;
		}
	} else {
		dest[0] = 0;
	}

	return src_len;
}
Exemplo n.º 5
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.º 6
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.º 7
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.º 8
0
static size_t interpret_long_filename(TALLOC_CTX *ctx,
					struct cli_state *cli,
					int level,
					const char *base_ptr,
					uint16_t recv_flags2,
					const char *p,
					const char *pdata_end,
					struct file_info *finfo,
					uint32 *p_resume_key,
					DATA_BLOB *p_last_name_raw)
{
	int len;
	size_t ret;
	const char *base = p;

	data_blob_free(p_last_name_raw);

	if (p_resume_key) {
		*p_resume_key = 0;
	}
	ZERO_STRUCTP(finfo);

	switch (level) {
		case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
			/* these dates are converted to GMT by
                           make_unix_date */
			if (pdata_end - base < 27) {
				return pdata_end - base;
			}
			finfo->ctime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->atime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->mtime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->size = IVAL(p,16);
			finfo->mode = CVAL(p,24);
			len = CVAL(p, 26);
			p += 27;
			if (recv_flags2 & FLAGS2_UNICODE_STRINGS) {
				p += ucs2_align(base_ptr, p, STR_UNICODE);
			}

			/* We can safely use len here (which is required by OS/2)
			 * and the NAS-BASIC server instead of +2 or +1 as the
			 * STR_TERMINATE flag below is
			 * actually used as the length calculation.
			 * The len is merely an upper bound.
			 * Due to the explicit 2 byte null termination
			 * in cli_receive_trans/cli_receive_nt_trans
			 * we know this is safe. JRA + kukks
			 */

			if (p + len > pdata_end) {
				return pdata_end - base;
			}

			/* the len+2 below looks strange but it is
			   important to cope with the differences
			   between win2000 and win9x for this call
			   (tridge) */
			ret = clistr_pull_talloc(ctx,
						base_ptr,
						recv_flags2,
						&finfo->name,
						p,
						len+2,
						STR_TERMINATE);
			if (ret == (size_t)-1) {
				return pdata_end - base;
			}
			p += ret;
			return PTR_DIFF(p, base);

		case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
			/* these dates are converted to GMT by
                           make_unix_date */
			if (pdata_end - base < 31) {
				return pdata_end - base;
			}
			finfo->ctime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->atime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->mtime_ts = convert_time_t_to_timespec(
				make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
			finfo->size = IVAL(p,16);
			finfo->mode = CVAL(p,24);
			len = CVAL(p, 30);
			p += 31;
			/* check for unisys! */
			if (p + len + 1 > pdata_end) {
				return pdata_end - base;
			}
			ret = clistr_pull_talloc(ctx,
						base_ptr,
						recv_flags2,
						&finfo->name,
						p,
					 	len,
						STR_NOALIGN);
			if (ret == (size_t)-1) {
				return pdata_end - base;
			}
			p += ret;
			return PTR_DIFF(p, base) + 1;

		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
		{
			size_t namelen, slen;

			if (pdata_end - base < 94) {
				return pdata_end - base;
			}

			p += 4; /* next entry offset */

			if (p_resume_key) {
				*p_resume_key = IVAL(p,0);
			}
			p += 4; /* fileindex */

			/* Offset zero is "create time", not "change time". */
			p += 8;
			finfo->atime_ts = interpret_long_date(p);
			p += 8;
			finfo->mtime_ts = interpret_long_date(p);
			p += 8;
			finfo->ctime_ts = interpret_long_date(p);
			p += 8;
			finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
			p += 8;
			p += 8; /* alloc size */
			finfo->mode = CVAL(p,0);
			p += 4;
			namelen = IVAL(p,0);
			p += 4;
			p += 4; /* EA size */
			slen = SVAL(p, 0);
			if (slen > 24) {
				/* Bad short name length. */
				return pdata_end - base;
			}
			p += 2;
			ret = clistr_pull_talloc(ctx,
						base_ptr,
						recv_flags2,
						&finfo->short_name,
						p,
						slen,
						STR_UNICODE);
			if (ret == (size_t)-1) {
				return pdata_end - base;
			}
			p += 24; /* short name? */
			if (p + namelen < p || p + namelen > pdata_end) {
				return pdata_end - base;
			}
			ret = clistr_pull_talloc(ctx,
						base_ptr,
						recv_flags2,
						&finfo->name,
						p,
				    		namelen,
						0);
			if (ret == (size_t)-1) {
				return pdata_end - base;
			}

			/* To be robust in the face of unicode conversion failures
			   we need to copy the raw bytes of the last name seen here.
			   Namelen doesn't include the terminating unicode null, so
			   copy it here. */

			if (p_last_name_raw) {
				*p_last_name_raw = data_blob(NULL, namelen+2);
				memcpy(p_last_name_raw->data, p, namelen);
				SSVAL(p_last_name_raw->data, namelen, 0);
			}
			return calc_next_entry_offset(base, pdata_end);
		}
	}

	DEBUG(1,("Unknown long filename format %d\n",level));
	return calc_next_entry_offset(base, pdata_end);
}