// 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; }
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()); } } } }
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()); } }
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; }