internal bool TryReadSqlValueInternal(SqlBuffer value, byte tdsType, int length, TdsParserStateObject stateObj) { switch (tdsType) { case TdsEnums.SQLBIT: case TdsEnums.SQLBITN: Debug.Assert(length == 1, "invalid length for SqlBoolean type!"); byte byteValue; if (!stateObj.TryReadByte(out byteValue)) { return false; } value.Boolean = (byteValue != 0); break; case TdsEnums.SQLINTN: if (length == 1) { goto case TdsEnums.SQLINT1; } else if (length == 2) { goto case TdsEnums.SQLINT2; } else if (length == 4) { goto case TdsEnums.SQLINT4; } else { goto case TdsEnums.SQLINT8; } case TdsEnums.SQLINT1: Debug.Assert(length == 1, "invalid length for SqlByte type!"); if (!stateObj.TryReadByte(out byteValue)) { return false; } value.Byte = byteValue; break; case TdsEnums.SQLINT2: Debug.Assert(length == 2, "invalid length for SqlInt16 type!"); short shortValue; if (!stateObj.TryReadInt16(out shortValue)) { return false; } value.Int16 = shortValue; break; case TdsEnums.SQLINT4: Debug.Assert(length == 4, "invalid length for SqlInt32 type!"); int intValue; if (!stateObj.TryReadInt32(out intValue)) { return false; } value.Int32 = intValue; break; case TdsEnums.SQLINT8: Debug.Assert(length == 8, "invalid length for SqlInt64 type!"); long longValue; if (!stateObj.TryReadInt64(out longValue)) { return false; } value.Int64 = longValue; break; case TdsEnums.SQLFLTN: if (length == 4) { goto case TdsEnums.SQLFLT4; } else { goto case TdsEnums.SQLFLT8; } case TdsEnums.SQLFLT4: Debug.Assert(length == 4, "invalid length for SqlSingle type!"); float singleValue; if (!stateObj.TryReadSingle(out singleValue)) { return false; } value.Single = singleValue; break; case TdsEnums.SQLFLT8: Debug.Assert(length == 8, "invalid length for SqlDouble type!"); double doubleValue; if (!stateObj.TryReadDouble(out doubleValue)) { return false; } value.Double = doubleValue; break; case TdsEnums.SQLMONEYN: if (length == 4) { goto case TdsEnums.SQLMONEY4; } else { goto case TdsEnums.SQLMONEY; } case TdsEnums.SQLMONEY: { int mid; uint lo; if (!stateObj.TryReadInt32(out mid)) { return false; } if (!stateObj.TryReadUInt32(out lo)) { return false; } long l = (((long)mid) << 0x20) + ((long)lo); value.SetToMoney(l); break; } case TdsEnums.SQLMONEY4: if (!stateObj.TryReadInt32(out intValue)) { return false; } value.SetToMoney(intValue); break; case TdsEnums.SQLDATETIMN: if (length == 4) { goto case TdsEnums.SQLDATETIM4; } else { goto case TdsEnums.SQLDATETIME; } case TdsEnums.SQLDATETIM4: ushort daypartShort, timepartShort; if (!stateObj.TryReadUInt16(out daypartShort)) { return false; } if (!stateObj.TryReadUInt16(out timepartShort)) { return false; } value.SetToDateTime(daypartShort, timepartShort * SqlDateTime.SQLTicksPerMinute); break; case TdsEnums.SQLDATETIME: int daypart; uint timepart; if (!stateObj.TryReadInt32(out daypart)) { return false; } if (!stateObj.TryReadUInt32(out timepart)) { return false; } value.SetToDateTime(daypart, (int)timepart); break; case TdsEnums.SQLUNIQUEID: { Debug.Assert(length == 16, "invalid length for SqlGuid type!"); byte[] b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } value.SqlGuid = new SqlGuid(b, true); // doesn't copy the byte array break; } case TdsEnums.SQLBINARY: case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLVARBINARY: case TdsEnums.SQLIMAGE: { // Note: Better not come here with plp data!! Debug.Assert(length <= TdsEnums.MAXSIZE); byte[] b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } value.SqlBinary = new SqlBinary(b, true); // doesn't copy the byte array break; } case TdsEnums.SQLVARIANT: if (!TryReadSqlVariant(value, length, stateObj)) { return false; } break; default: Debug.Assert(false, "Unknown SqlType!" + tdsType.ToString(CultureInfo.InvariantCulture)); break; } // switch return true; }
internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, TdsParserStateObject stateObj) { bool isPlp = md.metaType.IsPlp; byte tdsType = md.tdsType; Debug.Assert(isPlp || !IsNull(md.metaType, (ulong)length), "null value should not get here!"); if (isPlp) { // We must read the column value completely, no matter what length is passed in length = Int32.MaxValue; } switch (tdsType) { case TdsEnums.SQLDECIMALN: case TdsEnums.SQLNUMERICN: if (!TryReadSqlDecimal(value, length, md.precision, md.scale, stateObj)) { return false; } break; case TdsEnums.SQLUDT: throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString()); case TdsEnums.SQLBINARY: case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLVARBINARY: case TdsEnums.SQLIMAGE: byte[] b = null; // If varbinary(max), we only read the first chunk here, expecting the caller to read the rest if (isPlp) { // If we are given -1 for length, then we read the entire value, // otherwise only the requested amount, usually first chunk. int ignored; if (!stateObj.TryReadPlpBytes(ref b, 0, length, out ignored)) { return false; } } else { //Debug.Assert(length > 0 && length < (long)(Int32.MaxValue), "Bad length for column"); b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } } value.SqlBinary = new SqlBinary(b, true); // doesn't copy the byte array break; case TdsEnums.SQLCHAR: case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: if (!TryReadSqlStringValue(value, tdsType, length, md.encoding, isPlp, stateObj)) { return false; } break; case TdsEnums.SQLXMLTYPE: // We store SqlCachedBuffer here, so that we can return either SqlBinary, SqlString or SqlXmlReader. SqlCachedBuffer sqlBuf; if (!SqlCachedBuffer.TryCreate(md, this, stateObj, out sqlBuf)) { return false; } value.SqlCachedBuffer = sqlBuf; break; case TdsEnums.SQLDATE: case TdsEnums.SQLTIME: case TdsEnums.SQLDATETIME2: case TdsEnums.SQLDATETIMEOFFSET: if (!TryReadSqlDateTime(value, tdsType, length, md.scale, stateObj)) { return false; } break; default: Debug.Assert(!isPlp, "ReadSqlValue calling ReadSqlValueInternal with plp data"); if (!TryReadSqlValueInternal(value, tdsType, length, stateObj)) { return false; } break; } Debug.Assert((stateObj._longlen == 0) && (stateObj._longlenleft == 0), "ReadSqlValue did not read plp field completely, longlen =" + stateObj._longlen.ToString((IFormatProvider)null) + ",longlenleft=" + stateObj._longlenleft.ToString((IFormatProvider)null)); return true; }
private bool TryReadSqlDateTime(SqlBuffer value, byte tdsType, int length, byte scale, TdsParserStateObject stateObj) { byte[] datetimeBuffer = new byte[length]; if (!stateObj.TryReadByteArray(datetimeBuffer, 0, length)) { return false; } switch (tdsType) { case TdsEnums.SQLDATE: Debug.Assert(length == 3, "invalid length for date type!"); value.SetToDate(datetimeBuffer); break; case TdsEnums.SQLTIME: Debug.Assert(3 <= length && length <= 5, "invalid length for time type!"); value.SetToTime(datetimeBuffer, length, scale); break; case TdsEnums.SQLDATETIME2: Debug.Assert(6 <= length && length <= 8, "invalid length for datetime2 type!"); value.SetToDateTime2(datetimeBuffer, length, scale); break; case TdsEnums.SQLDATETIMEOFFSET: Debug.Assert(8 <= length && length <= 10, "invalid length for datetimeoffset type!"); value.SetToDateTimeOffset(datetimeBuffer, length, scale); break; default: Debug.Assert(false, "ReadSqlDateTime is called with the wrong tdsType"); break; } return true; }
private bool TryProcessSessionState(TdsParserStateObject stateObj, int length, SessionData sdata) { if (length < 5) { throw SQL.ParsingError(); } UInt32 seqNum; if (!stateObj.TryReadUInt32(out seqNum)) { return false; } if (seqNum == UInt32.MaxValue) { _connHandler.DoNotPoolThisConnection(); } byte status; if (!stateObj.TryReadByte(out status)) { return false; } if (status > 1) { throw SQL.ParsingError(); } bool recoverable = status != 0; length -= 5; while (length > 0) { byte stateId; if (!stateObj.TryReadByte(out stateId)) { return false; } int stateLen; byte stateLenByte; if (!stateObj.TryReadByte(out stateLenByte)) { return false; } if (stateLenByte < 0xFF) { stateLen = stateLenByte; } else { if (!stateObj.TryReadInt32(out stateLen)) { return false; } } byte[] buffer = null; lock (sdata._delta) { if (sdata._delta[stateId] == null) { buffer = new byte[stateLen]; sdata._delta[stateId] = new SessionStateRecord { _version = seqNum, _dataLength = stateLen, _data = buffer, _recoverable = recoverable }; sdata._deltaDirty = true; if (!recoverable) { checked { sdata._unrecoverableStatesCount++; } } } else { if (sdata._delta[stateId]._version <= seqNum) { SessionStateRecord sv = sdata._delta[stateId]; sv._version = seqNum; sv._dataLength = stateLen; if (sv._recoverable != recoverable) { if (recoverable) { Debug.Assert(sdata._unrecoverableStatesCount > 0, "Unrecoverable states count >0"); sdata._unrecoverableStatesCount--; } else { checked { sdata._unrecoverableStatesCount++; } } sv._recoverable = recoverable; } buffer = sv._data; if (buffer.Length < stateLen) { buffer = new byte[stateLen]; sv._data = buffer; } } } } if (buffer != null) { if (!stateObj.TryReadByteArray(buffer, 0, stateLen)) { return false; } } else { if (!stateObj.TrySkipBytes(stateLen)) return false; } if (stateLenByte < 0xFF) { length -= 2 + stateLen; } else { length -= 6 + stateLen; } } sdata.AssertUnrecoverableStateCountIsCorrect(); return true; }
private bool TryProcessLoginAck(TdsParserStateObject stateObj, out SqlLoginAck sqlLoginAck) { SqlLoginAck a = new SqlLoginAck(); sqlLoginAck = null; // read past interface type and version if (!stateObj.TrySkipBytes(1)) { return false; } byte[] b = new byte[TdsEnums.VERSION_SIZE]; if (!stateObj.TryReadByteArray(b, 0, b.Length)) { return false; } a.tdsVersion = (UInt32)((((((b[0] << 8) | b[1]) << 8) | b[2]) << 8) | b[3]); // bytes are in motorola order (high byte first) UInt32 majorMinor = a.tdsVersion & 0xff00ffff; UInt32 increment = (a.tdsVersion >> 16) & 0xff; // Server responds: // 0x07000000 -> Sphinx // Notice server response format is different for bwd compat // 0x07010000 -> Shiloh RTM // Notice server response format is different for bwd compat // 0x71000001 -> Shiloh SP1 // 0x72xx0002 -> Yukon RTM // information provided by S. Ashwin switch (majorMinor) { case TdsEnums.YUKON_MAJOR << 24 | TdsEnums.YUKON_RTM_MINOR: // Yukon if (increment != TdsEnums.YUKON_INCREMENT) { throw SQL.InvalidTDSVersion(); } break; case TdsEnums.KATMAI_MAJOR << 24 | TdsEnums.KATMAI_MINOR: if (increment != TdsEnums.KATMAI_INCREMENT) { throw SQL.InvalidTDSVersion(); } _isKatmai = true; break; case TdsEnums.DENALI_MAJOR << 24 | TdsEnums.DENALI_MINOR: if (increment != TdsEnums.DENALI_INCREMENT) { throw SQL.InvalidTDSVersion(); } _isDenali = true; break; default: throw SQL.InvalidTDSVersion(); } _isKatmai |= _isDenali; stateObj._outBytesUsed = stateObj._outputHeaderLen; byte len; if (!stateObj.TryReadByte(out len)) { return false; } if (!stateObj.TrySkipBytes(len * ADP.CharSize)) { return false; } if (!stateObj.TryReadByte(out a.majorVersion)) { return false; } if (!stateObj.TryReadByte(out a.minorVersion)) { return false; } byte buildNumHi, buildNumLo; if (!stateObj.TryReadByte(out buildNumHi)) { return false; } if (!stateObj.TryReadByte(out buildNumLo)) { return false; } a.buildNum = (short)((buildNumHi << 8) + buildNumLo); Debug.Assert(_state == TdsParserState.OpenNotLoggedIn, "ProcessLoginAck called with state not TdsParserState.OpenNotLoggedIn"); _state = TdsParserState.OpenLoggedIn; { if (_fMARS) { _resetConnectionEvent = new AutoResetEvent(true); } } // Fail if SSE UserInstance and we have not received this info. if (_connHandler.ConnectionOptions.UserInstance && ADP.IsEmpty(_connHandler.InstanceName)) { stateObj.AddError(new SqlError(0, 0, TdsEnums.FATAL_ERROR_CLASS, Server, SQLMessage.UserInstanceFailure(), "", 0)); ThrowExceptionAndWarning(stateObj); } sqlLoginAck = a; return true; }
private bool TryReadTwoBinaryFields(SqlEnvChange env, TdsParserStateObject stateObj) { // Used by ProcessEnvChangeToken byte byteLength; if (!stateObj.TryReadByte(out byteLength)) { return false; } env.newLength = byteLength; env.newBinValue = new byte[env.newLength]; if (!stateObj.TryReadByteArray(env.newBinValue, 0, env.newLength)) { return false; } if (!stateObj.TryReadByte(out byteLength)) { return false; } env.oldLength = byteLength; env.oldBinValue = new byte[env.oldLength]; if (!stateObj.TryReadByteArray(env.oldBinValue, 0, env.oldLength)) { return false; } // env.length includes 1 byte type token env.length = 3 + env.newLength + env.oldLength; return true; }
private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { // read feature ID byte featureId; do { if (!stateObj.TryReadByte(out featureId)) { return false; } if (featureId != TdsEnums.FEATUREEXT_TERMINATOR) { UInt32 dataLen; if (!stateObj.TryReadUInt32(out dataLen)) { return false; } byte[] data = new byte[dataLen]; if (dataLen > 0) { if (!stateObj.TryReadByteArray(data, 0, checked((int)dataLen))) { return false; } } _connHandler.OnFeatureExtAck(featureId, data); } } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR); return true; }
private int _columnsCount; // set to 0 if not used or > 0 for NBC rows internal bool TryInitialize(TdsParserStateObject stateObj, int columnsCount) { _columnsCount = columnsCount; // 1-8 columns need 1 byte // 9-16: 2 bytes, and so on int bitmapArrayLength = (columnsCount + 7) / 8; // allow reuse of previously allocated bitmap if (_nullBitmap == null || _nullBitmap.Length != bitmapArrayLength) { _nullBitmap = new byte[bitmapArrayLength]; } // read the null bitmap compression information from TDS if (!stateObj.TryReadByteArray(_nullBitmap, 0, _nullBitmap.Length)) { return false; } if (Bid.TraceOn) { Bid.Trace("<sc.TdsParserStateObject.NullBitmap.Initialize|INFO|ADV> %d#, NBCROW bitmap received, column count = %d\n", stateObj.ObjectID, columnsCount); Bid.TraceBin("<sc.TdsParserStateObject.NullBitmap.Initialize|INFO|ADV> NBCROW bitmap data: ", _nullBitmap, (UInt16)_nullBitmap.Length); } return true; }
private int _columnsCount; // set to 0 if not used or > 0 for NBC rows internal bool TryInitialize(TdsParserStateObject stateObj, int columnsCount) { _columnsCount = columnsCount; // 1-8 columns need 1 byte // 9-16: 2 bytes, and so on int bitmapArrayLength = (columnsCount + 7) / 8; // allow reuse of previously allocated bitmap if (_nullBitmap == null || _nullBitmap.Length != bitmapArrayLength) { _nullBitmap = new byte[bitmapArrayLength]; } // read the null bitmap compression information from TDS if (!stateObj.TryReadByteArray(_nullBitmap, 0, _nullBitmap.Length)) { return false; } return true; }
internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, TdsParserStateObject stateObj, SqlCommandColumnEncryptionSetting columnEncryptionOverride, string columnName) { bool isPlp = md.metaType.IsPlp; byte tdsType = md.tdsType; Debug.Assert(isPlp || !IsNull(md.metaType, (ulong)length), "null value should not get here!"); if (isPlp) { // We must read the column value completely, no matter what length is passed in length = Int32.MaxValue; } //DEVNOTE: When modifying the following routines (for deserialization) please pay attention to // deserialization code in DecryptWithKey () method and modify it accordingly. switch (tdsType) { case TdsEnums.SQLDECIMALN: case TdsEnums.SQLNUMERICN: if (!TryReadSqlDecimal(value, length, md.precision, md.scale, stateObj)) { return false; } break; case TdsEnums.SQLUDT: case TdsEnums.SQLBINARY: case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLVARBINARY: case TdsEnums.SQLIMAGE: byte[] b = null; // If varbinary(max), we only read the first chunk here, expecting the caller to read the rest if (isPlp) { // If we are given -1 for length, then we read the entire value, // otherwise only the requested amount, usually first chunk. int ignored; if (!stateObj.TryReadPlpBytes(ref b, 0, length, out ignored)) { return false; } } else { //Debug.Assert(length > 0 && length < (long)(Int32.MaxValue), "Bad length for column"); b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } } if (md.isEncrypted && ((columnEncryptionOverride == SqlCommandColumnEncryptionSetting.Enabled || columnEncryptionOverride == SqlCommandColumnEncryptionSetting.ResultSetOnly) || (columnEncryptionOverride == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _connHandler != null && _connHandler.ConnectionOptions != null && _connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled))) { try { // CipherInfo is present, decrypt and read byte[] unencryptedBytes = SqlSecurityUtility.DecryptWithKey(b, md.cipherMD, _connHandler.ConnectionOptions.DataSource); if (unencryptedBytes != null) { DeserializeUnencryptedValue(value, unencryptedBytes, md, stateObj, md.NormalizationRuleVersion); } } catch (Exception e) { throw SQL.ColumnDecryptionFailed(columnName, null, e); } } else { value.SqlBinary = new SqlBinary(b, true); // doesn't copy the byte array } break; case TdsEnums.SQLCHAR: case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: if (!TryReadSqlStringValue(value, tdsType, length, md.encoding, isPlp, stateObj)) { return false; } break; case TdsEnums.SQLXMLTYPE: // We store SqlCachedBuffer here, so that we can return either SqlBinary, SqlString or SqlXmlReader. SqlCachedBuffer sqlBuf; if (!SqlCachedBuffer.TryCreate(md, this, stateObj, out sqlBuf)) { return false; } value.SqlCachedBuffer = sqlBuf; break; case TdsEnums.SQLDATE: case TdsEnums.SQLTIME: case TdsEnums.SQLDATETIME2: case TdsEnums.SQLDATETIMEOFFSET: if (!TryReadSqlDateTime(value, tdsType, length, md.scale, stateObj)) { return false; } break; default: Debug.Assert(!isPlp, "ReadSqlValue calling ReadSqlValueInternal with plp data"); if (!TryReadSqlValueInternal(value, tdsType, length, stateObj)) { return false; } break; } Debug.Assert((stateObj._longlen == 0) && (stateObj._longlenleft == 0), "ReadSqlValue did not read plp field completely, longlen =" + stateObj._longlen.ToString((IFormatProvider)null) + ",longlenleft=" + stateObj._longlenleft.ToString((IFormatProvider)null)); return true; }
/// <summary> /// <para> Parses the TDS message to read single CIPHER_INFO entry.</para> /// </summary> internal bool TryReadCipherInfoEntry (TdsParserStateObject stateObj, out SqlTceCipherInfoEntry entry) { byte cekValueCount = 0; entry = new SqlTceCipherInfoEntry(ordinal: 0); // Read the DB ID int dbId; if (!stateObj.TryReadInt32(out dbId)) { return false; } // Read the keyID int keyId; if (!stateObj.TryReadInt32(out keyId)) { return false; } // Read the key version int keyVersion; if (!stateObj.TryReadInt32(out keyVersion)) { return false; } // Read the key MD Version byte[] keyMDVersion = new byte[8]; if (!stateObj.TryReadByteArray(keyMDVersion, 0, 8)) { return false; } // Read the value count if (!stateObj.TryReadByte (out cekValueCount)) { return false; } for (int i = 0; i < cekValueCount; i++) { // Read individual CEK values byte[] encryptedCek; string keyPath; string keyStoreName; byte algorithmLength; string algorithmName; ushort shortValue; byte byteValue; int length; // Read the length of encrypted CEK if (!stateObj.TryReadUInt16 (out shortValue)) { return false; } length = shortValue; encryptedCek = new byte[length]; // Read the actual encrypted CEK if (!stateObj.TryReadByteArray (encryptedCek, 0, length)) { return false; } // Read the length of key store name if (!stateObj.TryReadByte (out byteValue)) { return false; } length = byteValue; // And read the key store name now if (!stateObj.TryReadString(length, out keyStoreName)) { return false; } // Read the length of key Path if (!stateObj.TryReadUInt16 (out shortValue)) { return false; } length = shortValue; // Read the key path string if (!stateObj.TryReadString(length, out keyPath)) { return false; } // Read the length of the string carrying the encryption algo if (!stateObj.TryReadByte(out algorithmLength)) { return false; } length = (int)algorithmLength; // Read the string carrying the encryption algo (eg. RSA_PKCS_OAEP) if (!stateObj.TryReadString(length, out algorithmName)) { return false; } // Add this encrypted CEK blob to our list of encrypted values for the CEK entry.Add(encryptedCek, databaseId: dbId, cekId: keyId, cekVersion: keyVersion, cekMdVersion: keyMDVersion, keyPath: keyPath, keyStoreName: keyStoreName, algorithmName: algorithmName); } return true; }
private bool TryProcessFedAuthInfo(TdsParserStateObject stateObj, int tokenLen, out SqlFedAuthInfo sqlFedAuthInfo) { sqlFedAuthInfo = null; SqlFedAuthInfo tempFedAuthInfo = new SqlFedAuthInfo(); // Skip reading token length, since it has already been read in caller if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FEDAUTHINFO token stream length = {0}\n", tokenLen); } if (tokenLen < sizeof(uint)) { // the token must at least contain a DWORD indicating the number of info IDs Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream length too short for CountOfInfoIDs.\n"); throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForCountOfInfoIds, tokenLen); } // read how many FedAuthInfo options there are uint optionsCount; if (!stateObj.TryReadUInt32(out optionsCount)) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read CountOfInfoIDs in FEDAUTHINFO token stream.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadCountOfInfoIds); } tokenLen -= sizeof(uint); // remaining length is shortened since we read optCount if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> CountOfInfoIDs = {0}\n", optionsCount.ToString(CultureInfo.InvariantCulture)); } if (tokenLen > 0) { // read the rest of the token byte[] tokenData = new byte[tokenLen]; int totalRead = 0; bool successfulRead = stateObj.TryReadByteArray(tokenData, 0, tokenLen, out totalRead); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Read rest of FEDAUTHINFO token stream: {0}\n", BitConverter.ToString(tokenData, 0, totalRead)); } if (!successfulRead || totalRead != tokenLen) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FEDAUTHINFO token stream. Attempted to read {0} bytes, actually read {1}\n", tokenLen, totalRead); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadTokenStream); } // each FedAuthInfoOpt is 9 bytes: // 1 byte for FedAuthInfoID // 4 bytes for FedAuthInfoDataLen // 4 bytes for FedAuthInfoDataOffset // So this is the index in tokenData for the i-th option const uint optionSize = 9; // the total number of bytes for all FedAuthInfoOpts together uint totalOptionsSize = checked(optionsCount * optionSize); for (uint i = 0; i < optionsCount; i++) { uint currentOptionOffset = checked(i * optionSize); byte id = tokenData[currentOptionOffset]; uint dataLen = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 1))); uint dataOffset = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 5))); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoOpt: ID={0}, DataLen={1}, Offset={2}\n", id, dataLen.ToString(CultureInfo.InvariantCulture), dataOffset.ToString(CultureInfo.InvariantCulture)); } // offset is measured from optCount, so subtract to make offset measured // from the beginning of tokenData checked { dataOffset -= sizeof(uint); } // if dataOffset points to a region within FedAuthInfoOpt or after the end of the token, throw if (dataOffset < totalOptionsSize || dataOffset >= tokenLen) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoDataOffset points to an invalid location.\n"); throw SQL.ParsingErrorOffset(ParsingErrorState.FedAuthInfoInvalidOffset, unchecked((int)dataOffset)); } // try to read data and throw if the arguments are bad, meaning the server sent us a bad token string data; try { data = System.Text.Encoding.Unicode.GetString(tokenData, checked((int)dataOffset), checked((int)dataLen)); } catch (ArgumentOutOfRangeException e) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FedAuthInfoData.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadData, e); } catch (ArgumentException e) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoData is not in unicode format.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDataNotUnicode, e); } if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoData: {0}\n", data); } // store data in tempFedAuthInfo switch ((TdsEnums.FedAuthInfoId)id) { case TdsEnums.FedAuthInfoId.Spn: tempFedAuthInfo.spn = data; break; case TdsEnums.FedAuthInfoId.Stsurl: tempFedAuthInfo.stsurl = data; break; default: if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Ignoring unknown federated authentication info option: {0}\n", id); } break; } } } else { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream is not long enough to contain the data it claims to.\n"); throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForData, tokenLen); } Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Processed FEDAUTHINFO token stream: {0}\n", tempFedAuthInfo.ToString()); if (String.IsNullOrWhiteSpace(tempFedAuthInfo.stsurl) || String.IsNullOrWhiteSpace(tempFedAuthInfo.spn)) { // We should be receiving both stsurl and spn Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream does not contain both STSURL and SPN.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDoesNotContainStsurlAndSpn); } sqlFedAuthInfo = tempFedAuthInfo; return true; }
private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { // read feature ID byte featureId; do { if (!stateObj.TryReadByte(out featureId)) { return false; } if (featureId != TdsEnums.FEATUREEXT_TERMINATOR) { UInt32 dataLen; if (!stateObj.TryReadUInt32(out dataLen)) { return false; } byte[] data = new byte[dataLen]; if (dataLen > 0) { if (!stateObj.TryReadByteArray(data, 0, checked ((int)dataLen))) { return false; } } _connHandler.OnFeatureExtAck(featureId, data); } } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR); // Check if column encryption was on and feature wasn't acknowledged. if (_connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled && !IsColumnEncryptionSupported) { throw SQL.TceNotSupported (); } return true; }
private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, out SqlEnvChange[] sqlEnvChange) { // There could be multiple environment change messages following this token. byte byteLength; int processedLength = 0; int nvalues = 0; SqlEnvChange[] envarray = new SqlEnvChange[3]; // Why is this hardcoded to 3? sqlEnvChange = null; while (tokenLength > processedLength) { if (nvalues >= envarray.Length) { // This is a rare path. Most of the time we will have 1 or 2 envchange data streams. SqlEnvChange[] newenvarray = new SqlEnvChange[envarray.Length + 3]; for (int ii = 0; ii < envarray.Length; ii++) newenvarray[ii] = envarray[ii]; envarray = newenvarray; } SqlEnvChange env = new SqlEnvChange(); if (!stateObj.TryReadByte(out env.type)) { return false; } envarray[nvalues] = env; nvalues++; switch (env.type) { case TdsEnums.ENV_DATABASE: case TdsEnums.ENV_LANG: if (!TryReadTwoStringFields(env, stateObj)) { return false; } break; case TdsEnums.ENV_CHARSET: // we copied this behavior directly from luxor - see charset envchange // section from sqlctokn.c Debug.Assert(!_isShiloh, "Received ENV_CHARSET on non 7.0 server!"); if (!TryReadTwoStringFields(env, stateObj)) { return false; } if (env.newValue == TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_STRING) { _defaultCodePage = TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_VALUE; _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage); } else { Debug.Assert(env.newValue.Length > TdsEnums.CHARSET_CODE_PAGE_OFFSET, "TdsParser.ProcessEnvChange(): charset value received with length <=10"); string stringCodePage = env.newValue.Substring(TdsEnums.CHARSET_CODE_PAGE_OFFSET); _defaultCodePage = Int32.Parse(stringCodePage, NumberStyles.Integer, CultureInfo.InvariantCulture); _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage); } break; case TdsEnums.ENV_PACKETSIZE: // take care of packet size right here Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); if (!TryReadTwoStringFields(env, stateObj)) { // Changing packet size does not support retry, should not pend" throw SQL.SynchronousCallMayNotPend(); } // Only set on physical state object - this should only occur on LoginAck prior // to MARS initialization! Int32 packetSize = Int32.Parse(env.newValue, NumberStyles.Integer, CultureInfo.InvariantCulture); if (_physicalStateObj.SetPacketSize(packetSize)) { // If packet size changed, we need to release our SNIPackets since // those are tied to packet size of connection. _physicalStateObj.ClearAllWritePackets(); // Update SNI ConsumerInfo value to be resulting packet size UInt32 unsignedPacketSize = (UInt32) packetSize; UInt32 result = SNINativeMethodWrapper.SNISetInfo(_physicalStateObj.Handle, SNINativeMethodWrapper.QTypes.SNI_QUERY_CONN_BUFSIZE, ref unsignedPacketSize); Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SNISetInfo"); } break; case TdsEnums.ENV_LOCALEID: // if (!TryReadTwoStringFields(env, stateObj)) { return false; } _defaultLCID = Int32.Parse(env.newValue, NumberStyles.Integer, CultureInfo.InvariantCulture); break; case TdsEnums.ENV_COMPFLAGS: if (!TryReadTwoStringFields(env, stateObj)) { return false; } break; case TdsEnums.ENV_COLLATION: Debug.Assert(env.newLength == 5 || env.newLength == 0, "Improper length in new collation!"); if (!stateObj.TryReadByte(out byteLength)) { return false; } env.newLength = byteLength; if (env.newLength == 5) { if (!TryProcessCollation(stateObj, out env.newCollation)) { return false; } // give the parser the new collation values in case parameters don't specify one _defaultCollation = env.newCollation; int newCodePage = GetCodePage(env.newCollation, stateObj); if (newCodePage != _defaultCodePage) { _defaultCodePage = newCodePage; _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage); } _defaultLCID = env.newCollation.LCID; } if (!stateObj.TryReadByte(out byteLength)) { return false; } env.oldLength = byteLength; Debug.Assert(env.oldLength == 5 || env.oldLength == 0, "Improper length in old collation!"); if (env.oldLength == 5) { if (!TryProcessCollation(stateObj, out env.oldCollation)) { return false; } } env.length = 3 + env.newLength + env.oldLength; break; case TdsEnums.ENV_BEGINTRAN: case TdsEnums.ENV_COMMITTRAN: case TdsEnums.ENV_ROLLBACKTRAN: case TdsEnums.ENV_ENLISTDTC: case TdsEnums.ENV_DEFECTDTC: case TdsEnums.ENV_TRANSACTIONENDED: Debug.Assert(_isYukon, "Received new ENVCHANGE transaction/DTC token on pre 9.0 server!"); if (!stateObj.TryReadByte(out byteLength)) { return false; } env.newLength = byteLength; Debug.Assert(env.newLength == 0 || env.newLength == 8, "Improper length for new transaction id!"); if (env.newLength > 0) { if (!stateObj.TryReadInt64(out env.newLongValue)) { return false; } Debug.Assert(env.newLongValue != SqlInternalTransaction.NullTransactionId, "New transaction id is null?"); // the server guarantees that zero is an invalid transaction id. } else { env.newLongValue = SqlInternalTransaction.NullTransactionId; // the server guarantees that zero is an invalid transaction id. } if (!stateObj.TryReadByte(out byteLength)) { return false; } env.oldLength = byteLength; Debug.Assert(env.oldLength == 0 || env.oldLength == 8, "Improper length for old transaction id!"); if (env.oldLength > 0) { if (!stateObj.TryReadInt64(out env.oldLongValue)) { return false; } Debug.Assert(env.oldLongValue != SqlInternalTransaction.NullTransactionId, "Old transaction id is null?"); // the server guarantees that zero is an invalid transaction id. } else { env.oldLongValue = SqlInternalTransaction.NullTransactionId; // the server guarantees that zero is an invalid transaction id. } // env.length includes 1 byte type token env.length = 3 + env.newLength + env.oldLength; break; case TdsEnums.ENV_LOGSHIPNODE: // env.newBinValue is secondary node, env.oldBinValue is witness node // comes before LoginAck so we can't assert this if (!TryReadTwoStringFields(env, stateObj)) { return false; } break; case TdsEnums.ENV_PROMOTETRANSACTION: Debug.Assert(_isYukon, "Received new ENVCHANGE tokens on pre 9.0 server!"); if (!stateObj.TryReadInt32(out env.newLength)) { // new value has 4 byte length return false; } env.newBinValue = new byte[env.newLength]; if (!stateObj.TryReadByteArray(env.newBinValue, 0, env.newLength)) { // read new value with 4 byte length return false; } if (!stateObj.TryReadByte(out byteLength)) { return false; } env.oldLength = byteLength; Debug.Assert(0 == env.oldLength, "old length should be zero"); // env.length includes 1 byte for type token env.length = 5 + env.newLength; break; case TdsEnums.ENV_TRANSACTIONMANAGERADDRESS: case TdsEnums.ENV_SPRESETCONNECTIONACK: // Debug.Assert(_isYukon, "Received new ENVCHANGE tokens on pre 9.0 server!"); if (!TryReadTwoBinaryFields(env, stateObj)) { return false; } break; case TdsEnums.ENV_USERINSTANCE: Debug.Assert(!_isYukon, "Received ENV_USERINSTANCE on non 9.0 server!"); if (!TryReadTwoStringFields(env, stateObj)) { return false; } break; case TdsEnums.ENV_ROUTING: ushort newLength; if (!stateObj.TryReadUInt16(out newLength)) { return false; } env.newLength = newLength; byte protocol; if (!stateObj.TryReadByte(out protocol)) { return false; } ushort port; if (!stateObj.TryReadUInt16(out port)) { return false; } UInt16 serverLen; if (!stateObj.TryReadUInt16(out serverLen)) { return false; } string serverName; if (!stateObj.TryReadString(serverLen, out serverName)) { return false; } env.newRoutingInfo = new RoutingInfo(protocol, port, serverName); UInt16 oldLength; if (!stateObj.TryReadUInt16(out oldLength)) { return false; } if (!stateObj.TrySkipBytes(oldLength)) { return false; } env.length = env.newLength + oldLength + 5; // 5=2*sizeof(UInt16)+sizeof(byte) [token+newLength+oldLength] break; default: Debug.Assert(false, "Unknown environment change token: " + env.type); break; } processedLength += env.length; } sqlEnvChange = envarray; return true; }