Example #1
0
// check if OS have support for IPv6 protocol
bool isIPv6supported()
{
	INT proto[] = {IPPROTO_TCP, 0};

	Firebird::HalfStaticArray<char, sizeof(WSAPROTOCOL_INFO) * 4> buf;

	DWORD len = buf.getCapacity();
	LPWSAPROTOCOL_INFO pi = (LPWSAPROTOCOL_INFO) buf.getBuffer(len);

	int n = WSAEnumProtocols(proto, pi, &len);

	if (n == SOCKET_ERROR && GetLastError() == WSAENOBUFS)
	{
		pi = (LPWSAPROTOCOL_INFO) buf.getBuffer(len);
		n = WSAEnumProtocols(proto, pi, &len);
	}

	if (n == SOCKET_ERROR)
		return false;

	for (int i = 0; i < n; i++)
	{
		if (pi[i].iAddressFamily == AF_INET6 && pi[i].iProtocol == IPPROTO_TCP)
			return true;
	}

	WSASetLastError(0);
	return false;
}
Example #2
0
void INTL_adjust_text_descriptor(thread_db* tdbb, dsc* desc)
{
/**************************************
 *
 *      I N T L _ a d j u s t _ t e x t _ d e s c r i p t o r
 *
 **************************************
 *
 * Functional description
 *      This function receives a text descriptor with
 *      dsc_length = numberOfCharacters * maxBytesPerChar
 *      and change dsc_length to number of bytes used by the string.
 *
 **************************************/
	if (desc->dsc_dtype == dtype_text)
	{
		SET_TDBB(tdbb);

		USHORT ttype = INTL_TTYPE(desc);

		CharSet* charSet = INTL_charset_lookup(tdbb, ttype);

		if (charSet->isMultiByte())
		{
			Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> buffer;

			if (charSet->getFlags() & CHARSET_LEGACY_SEMANTICS)
			{
				desc->dsc_length = charSet->substring(TEXT_LEN(desc), desc->dsc_address, TEXT_LEN(desc),
										buffer.getBuffer(TEXT_LEN(desc) * charSet->maxBytesPerChar()), 0,
										TEXT_LEN(desc));

				const ULONG maxLength = TEXT_LEN(desc) / charSet->maxBytesPerChar();
				ULONG charLength = charSet->length(desc->dsc_length, desc->dsc_address, true);

				while (charLength > maxLength)
				{
					if (desc->dsc_address[desc->dsc_length - 1] == *charSet->getSpace())
					{
						--desc->dsc_length;
						--charLength;
					}
					else
						break;
				}
			}
			else
			{
				desc->dsc_length = charSet->substring(TEXT_LEN(desc), desc->dsc_address,
										TEXT_LEN(desc), buffer.getBuffer(TEXT_LEN(desc)), 0,
										TEXT_LEN(desc) / charSet->maxBytesPerChar());
			}
		}
	}
}
Example #3
0
	void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt)
	{
		MutexLockGuard g(holdersMutex, FB_FUNCTION);

		Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
		unsigned int length = knownHolders.getCount();
		IKeyHolderPlugin** vector = holdersVector.getBuffer(length);
		for (unsigned i = 0; i < length; ++i)
		{
			vector[i] = knownHolders[i].getPlugin();
		}

		LocalStatus st;
		crypt->setKey(&st, length, vector);
		if (!st.isSuccess())
		{
			status_exception::raise(st.get());
		}
	}
Example #4
0
ISC_STATUS filter_transliterate_text(USHORT action, BlobControl* control)
{
/**************************************
 *
 *	f i l t e r _ t r a n s l i t e r a t e _ t e x t
 *
 **************************************
 *
 * Functional description
 *	Get next segment from a text blob.
 *	Convert the text from one character set to another.
 *
 *	The usage of the variable ctl_data slots:
 *	    ctl_data [0]	Pointer to ctlaux structure below,
 *
 **************************************/
	struct ctlaux
	{
		CsConvert ctlaux_obj1;				// Intl object that does tx for us
		USHORT ctlaux_init_action;			// isc_blob_filter_open or isc_blob_filter_create?
		BYTE *ctlaux_buffer1;				// Temporary buffer for transliteration
		BlobControl* ctlaux_subfilter;		// For chaining transliterate filters
		ISC_STATUS ctlaux_source_blob_status;	// marks when source is EOF, etc
		USHORT ctlaux_buffer1_len;			// size of ctlaux_buffer1 in bytes
		USHORT ctlaux_expansion_factor;		// factor for text expand/contraction
		USHORT ctlaux_buffer1_unused;		// unused bytes in ctlaux_buffer1
	};

	thread_db* tdbb = NULL;
	// Note: Cannot pass tdbb without API change to user filters

	const USHORT EXP_SCALE		= 128;		// to keep expansion non-floating

	ctlaux* aux = (ctlaux*) control->ctl_data[0];

	BlobControl* source;
	ISC_STATUS status;
	ULONG err_position;
	SSHORT source_cs, dest_cs;
	USHORT result_length;

	switch (action)
	{
	case isc_blob_filter_open:
	case isc_blob_filter_create:
		for (SSHORT i = 0; i < FB_NELEM(control->ctl_data); i++)
			control->ctl_data[i] = 0;
		aux = NULL;

		source = control->ctl_handle;
		control->ctl_number_segments = source->ctl_number_segments;

		source_cs = control->ctl_from_sub_type;
		dest_cs = control->ctl_to_sub_type;

		aux = (ctlaux*) gds__alloc((SLONG) sizeof(*aux));
		// FREE: on isc_blob_filter_close in this routine
		if (!aux)				// NOMEM:
			return isc_virmemexh;
#ifdef DEBUG_GDS_ALLOC
		// BUG 7907: this is not freed in error cases
		gds_alloc_flag_unfreed(aux);
#endif
		control->ctl_data[0] = (IPTR) aux;

		aux->ctlaux_init_action = action;
		aux->ctlaux_source_blob_status = FB_SUCCESS;
		aux->ctlaux_buffer1_unused = 0;
		aux->ctlaux_expansion_factor = EXP_SCALE * 1;

		SET_TDBB(tdbb);
		aux->ctlaux_obj1 = INTL_convert_lookup(tdbb, dest_cs, source_cs);

		if (action == isc_blob_filter_open)
		{
			// hvlad: avoid possible overflow of USHORT variables converting long
			// blob segments into multibyte encoding
			// Also buffer must contain integer number of utf16 characters as we
			// do transliteration via utf16 character set
			// (see assert at start of UnicodeUtil::utf16ToUtf8 for example)
			const ULONG max_seg = aux->ctlaux_obj1.convertLength(source->ctl_max_segment);
			control->ctl_max_segment = MIN(MAX_USHORT - sizeof(ULONG) + 1, max_seg);

			if (source->ctl_max_segment && control->ctl_max_segment)
				aux->ctlaux_expansion_factor =
					(EXP_SCALE * control->ctl_max_segment) / source->ctl_max_segment;
			else
				aux->ctlaux_expansion_factor = (EXP_SCALE * 1);

			fb_assert(aux->ctlaux_expansion_factor != 0);

			control->ctl_total_length =
				source->ctl_total_length * aux->ctlaux_expansion_factor / EXP_SCALE;

			aux->ctlaux_buffer1_len = MAX(control->ctl_max_segment, source->ctl_max_segment);
			aux->ctlaux_buffer1_len =
				MAX(aux->ctlaux_buffer1_len, (80 * aux->ctlaux_expansion_factor) / EXP_SCALE);
		}
		else
		{
			// isc_blob_filter_create
			// In a create, the source->ctl_max_segment size isn't set (as
			// nothing has been written!).  Therefore, take a best guess
			// for an appropriate buffer size, allocate that, and re-allocate
			// later if we guess wrong.
			const USHORT tmp = aux->ctlaux_obj1.convertLength(128);
			aux->ctlaux_expansion_factor = (EXP_SCALE * tmp) / 128;

			fb_assert(aux->ctlaux_expansion_factor != 0);

			aux->ctlaux_buffer1_len = 80 * aux->ctlaux_expansion_factor / EXP_SCALE;
		}

		// Allocate the temporary buffer  - make sure it is big enough for
		// either source or destination, and at least 80 bytes in size

		aux->ctlaux_buffer1_len = MAX(aux->ctlaux_buffer1_len, 80);
		fb_assert(aux->ctlaux_buffer1_len != 0);

		aux->ctlaux_buffer1 = (BYTE*) gds__alloc((SLONG) aux->ctlaux_buffer1_len);
		// FREE: on isc_blob_filter_close in this procedure
		if (!aux->ctlaux_buffer1)	// NOMEM:
			return isc_virmemexh;

#ifdef DEBUG_GDS_ALLOC
		// BUG 7907: this is not freed in error cases
		gds_alloc_flag_unfreed(aux->ctlaux_buffer1);
#endif

		return FB_SUCCESS;

	case isc_blob_filter_close:
		if (aux)
		{
			// ASF: Raise error at close functions is something bad,
			// but I know no better thing to do here.
			if (aux->ctlaux_init_action == isc_blob_filter_create && aux->ctlaux_buffer1_unused != 0)
			{
				return isc_transliteration_failed;
			}

			if (aux->ctlaux_buffer1)
			{
				gds__free(aux->ctlaux_buffer1);
				aux->ctlaux_buffer1 = NULL;
				aux->ctlaux_buffer1_len = 0;
			}

			gds__free(aux);
			control->ctl_data[0] = 0;
			aux = NULL;
		}

		return FB_SUCCESS;

	case isc_blob_filter_get_segment:
		// Fall through to handle get_segment below
		break;

	case isc_blob_filter_put_segment:
		{
			USHORT len = control->ctl_buffer_length;
			Firebird::HalfStaticArray<BYTE, BUFFER_MEDIUM> buffer;
			bool first = true;
			BYTE* p;

			while (len || aux->ctlaux_buffer1_unused)
			{
				if (aux->ctlaux_buffer1_unused != 0)
				{
					p = buffer.getBuffer(aux->ctlaux_buffer1_unused + len);
					memcpy(p, aux->ctlaux_buffer1, aux->ctlaux_buffer1_unused);
					memcpy(p + aux->ctlaux_buffer1_unused, control->ctl_buffer, len);
					len += aux->ctlaux_buffer1_unused;
				}
				else
					p = control->ctl_buffer;

				// Now convert from the input buffer into the temporary buffer

				// How much space do we need to convert?
				const ULONG cvt_len = aux->ctlaux_obj1.convertLength(len);
				result_length = MIN(MAX_USHORT, cvt_len);

				// Allocate a new buffer if we don't have enough
				if (result_length > aux->ctlaux_buffer1_len)
				{
					gds__free(aux->ctlaux_buffer1);
					aux->ctlaux_buffer1_len = result_length;
					aux->ctlaux_buffer1 = (BYTE *) gds__alloc((SLONG) result_length);
					// FREE: above & isc_blob_filter_close in this routine
					if (!aux->ctlaux_buffer1)	// NOMEM:
						return isc_virmemexh;
				}

				// convert the text

				try
				{
					err_position = len;
					result_length = aux->ctlaux_obj1.convert(len, p,
						aux->ctlaux_buffer1_len, aux->ctlaux_buffer1, &err_position);
				}
				catch (const Firebird::status_exception&)
				{
					return isc_transliteration_failed;
				}

				if (len > 0 && err_position == 0)
				{
					if (first)
						return isc_transliteration_failed;

					// Those bytes should be written in the next put or rejected in
					// close - CORE-2785.
					break;
				}

				// hand the text off to the next stage of the filter

				status = caller(isc_blob_filter_put_segment, control, result_length,
								aux->ctlaux_buffer1, NULL);

				if (status)
					return status;

				aux->ctlaux_buffer1_unused = len - err_position;

				if (aux->ctlaux_buffer1_unused != 0)
					memmove(aux->ctlaux_buffer1, p + err_position, aux->ctlaux_buffer1_unused);

				// update local control variables for segment length

				if (result_length > control->ctl_max_segment)
					control->ctl_max_segment = result_length;

				control->ctl_total_length += result_length;
				control->ctl_number_segments++;

				len = 0;
				first = false;
			}

			return FB_SUCCESS;
		}

	case isc_blob_filter_seek:
		return isc_uns_ext;

	case isc_blob_filter_alloc:
	case isc_blob_filter_free:
		return FB_SUCCESS;

	default:
		BUGCHECK(289);			// Unknown blob filter ACTION
		return isc_uns_ext;
	}

	// Drop thru for isc_blob_filter_get_segment.

	// Do we already have enough bytes in temp buffer to fill output buffer?

	bool can_use_more;
	USHORT length = aux->ctlaux_buffer1_unused;
	if (length)
	{
		if (control->ctl_buffer_length < (length * aux->ctlaux_expansion_factor / EXP_SCALE))
		{
			// No need to fetch more bytes, we have enough pending
			can_use_more = false;
		}
		else
			can_use_more = true;

		// Always keep a minimal count of bytes in the input buffer,
		// to prevent the case of truncated characters.
		if (length < 4)
			can_use_more = true;
	}

	/* Load data into the temporary buffer if,
	a) we've finished the current segment (no data left in buffer)
	b) We haven't finished reading the current segment from the
		source and could use more data for the forthcoming convert
		(We don't want to blindly keep topping off this buffer if we
		already have more than we can use) */

	USHORT bytes_read_from_source = 0;

	///if (!length || (can_use_more && (aux->ctlaux_source_blob_status == isc_segment)))
	if (!length || can_use_more)
	{
		// Get a segment, or partial segment, from the source
		// into the temporary buffer

		status = caller(isc_blob_filter_get_segment,
						control,
						(USHORT) MIN((aux->ctlaux_buffer1_len - length), control->ctl_buffer_length),
						aux->ctlaux_buffer1 + length,
						&bytes_read_from_source);

		switch (status)
		{
		case isc_segment:		// source has more segment bytes
			aux->ctlaux_source_blob_status = status;
			break;
		case isc_segstr_eof:	// source blob is finished
			if (length == 0)	// are we done too? *
				return isc_segstr_eof;
			aux->ctlaux_source_blob_status = FB_SUCCESS;
			break;
		case 0:                 // complete segment in buffer
			aux->ctlaux_source_blob_status = FB_SUCCESS;
			break;
		default:				// general error
			return status;
		}

		length += bytes_read_from_source;
	}

	// Now convert from the temporary buffer into the destination buffer.

	try
	{
		err_position = length;
		result_length = aux->ctlaux_obj1.convert(length, aux->ctlaux_buffer1,
						control->ctl_buffer_length, control->ctl_buffer,
						&err_position);
	}
	catch (const Firebird::status_exception&)
	{
		return isc_transliteration_failed;
	}

	if (err_position == 0 && bytes_read_from_source != 0 && length != 0 && length < 4)
	{
		// We don't have sufficient bytes to always transliterate a character.
		// A bad input on the first character is unrecoverable, so we cache
		// the bytes for the next read.
		result_length = 0;
	}
	else if (err_position < length)
	{
		// Bad input *might* be due to input buffer truncation in the middle
		// of a character, so shuffle bytes, add some more data, and try again.
		// If we already tried that then it's really some bad input.

		if (err_position == 0)
			return isc_transliteration_failed;
	}

	const USHORT unused_len = (err_position >= length) ? 0 : length - err_position;
	control->ctl_segment_length = result_length;
	if (unused_len)
		memcpy(aux->ctlaux_buffer1, aux->ctlaux_buffer1 + err_position, unused_len);
	aux->ctlaux_buffer1_unused = unused_len;

	// update local control variables for segment length

	if (result_length > control->ctl_max_segment)
		control->ctl_max_segment = result_length;

	// No need up update ctl_number_segments as this filter doesn't change it.
	// No need to update ctl_total_length as we calculated an estimate on entry.

	// see if we still have data we couldn't send to application

	if (unused_len)
		return isc_segment;		// can't fit all data into user buffer

	// We handed back all our data, but did we GET all the data
	// from the source?

	return (aux->ctlaux_source_blob_status == isc_segment) ? isc_segment : FB_SUCCESS;
}