/// <summary> /// Inflate the token /// NOTE: This operation is not continuable and assumes that the entire token is available in the stream /// </summary> /// <param name="source">Stream to inflate the token from</param> /// <returns>TRUE if inflation is complete</returns> public override bool Inflate(Stream source) { // Read packet length uint length = TDSUtilities.ReadUInt(source); // Read TDS version string tdsVersion = String.Format("{0:X}", TDSUtilities.ReadUInt(source)); // Consturct TDS version TDSVersion = new Version(int.Parse(tdsVersion.Substring(0, 1)), int.Parse(tdsVersion.Substring(1, 1)), Convert.ToInt32(tdsVersion.Substring(2, 2), 16), Convert.ToInt32(tdsVersion.Substring(4, 4), 16)); // Read packet length PacketSize = TDSUtilities.ReadUInt(source); // Read client program version ClientProgramVersion = TDSUtilities.ReadUInt(source); // Read client program identifier ClientPID = TDSUtilities.ReadUInt(source); // Read connection identifier ConnectionID = TDSUtilities.ReadUInt(source); // Instantiate the first optional flags OptionalFlags1 = new TDSLogin7TokenOptionalFlags1((byte)source.ReadByte()); // Instantiate the second optional flags OptionalFlags2 = new TDSLogin7TokenOptionalFlags2((byte)source.ReadByte()); // Instantiate type flags TypeFlags = new TDSLogin7TokenTypeFlags((byte)source.ReadByte()); // Instantiate the third optional flags OptionalFlags3 = new TDSLogin7TokenOptionalFlags3((byte)source.ReadByte()); // Read client time zone ClientTimeZone = TDSUtilities.ReadInt(source); // Read client locale identifier ClientLCID = TDSUtilities.ReadUInt(source); // Prepare a collection of property values that will be set later IList <TDSLogin7TokenOffsetProperty> variableProperties = new List <TDSLogin7TokenOffsetProperty>(); // Read client host name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("HostName"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read user name and password variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("UserID"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Password"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read application name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ApplicationName"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read server name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ServerName"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Check if extension is used if (OptionalFlags3.ExtensionFlag) { // Read Feature extension. Note that this is just an offset of the value, not the value itself variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("FeatureExt"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source), true)); } else { // Skip unused TDSUtilities.ReadUShort(source); TDSUtilities.ReadUShort(source); } // Read client library name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("LibraryName"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read language variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Language"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read database variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Database"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); ClientID = new byte[6]; // Read unique client identifier source.Read(ClientID, 0, ClientID.Length); // Read SSPI blob variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("SSPI"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read database file to be attached variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("AttachDatabaseFile"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read password change variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ChangePassword"), TDSUtilities.ReadUShort(source), TDSUtilities.ReadUShort(source))); // Read long SSPI uint sspiLength = TDSUtilities.ReadUInt(source); // At this point we surpassed the fixed packet length long inflationOffset = FixedPacketLength; // Order strings in ascending order by offset // For the most cases this should not change the order of the options in the stream, but just in case variableProperties = variableProperties.OrderBy(p => p.Position).ToList(); // We can't use "foreach" because FeatureExt processing changes the collection hence we can only go index-based way int iCurrentProperty = 0; // Iterate over each property while (iCurrentProperty < variableProperties.Count) { // Get the property at the indexed position TDSLogin7TokenOffsetProperty property = variableProperties[iCurrentProperty]; // Check if length is positive if (property.Length == 0) { // Move to the next propety iCurrentProperty++; continue; } // Ensure that current offset points to the option while (inflationOffset < property.Position) { // Read the stream source.ReadByte(); // Advance position inflationOffset++; } // Check special properties if (property.Property.Name == "Password" || property.Property.Name == "ChangePassword") { // Read passwod string property.Property.SetValue(this, TDSUtilities.ReadPasswordString(source, (ushort)(property.Length * 2)), null); // Advance the position inflationOffset += (property.Length * 2); } else if (property.Property.Name == "SSPI") { // If cbSSPI < USHRT_MAX, then this length MUST be used for SSPI and cbSSPILong MUST be ignored. // If cbSSPI == USHRT_MAX, then cbSSPILong MUST be checked. if (property.Length == ushort.MaxValue) { // If cbSSPILong > 0, then that value MUST be used. If cbSSPILong ==0, then cbSSPI (USHRT_MAX) MUST be used. if (sspiLength > 0) { // We don't know how to handle SSPI packets that exceed TDS packet size throw new NotSupportedException("Long SSPI blobs are not supported yet"); } } // Use short length instead sspiLength = property.Length; // Allocate buffer for SSPI data SSPI = new byte[sspiLength]; // Read SSPI blob source.Read(SSPI, 0, SSPI.Length); // Advance the position inflationOffset += sspiLength; } else if (property.Property.Name == "FeatureExt") { // Check if this is the property or a pointer to the property if (property.IsOffsetOffset) { // Read the actual offset of the feature extension property.Position = TDSUtilities.ReadUInt(source); // Mark that now we have actual value property.IsOffsetOffset = false; // Advance the position inflationOffset += sizeof(uint); // Re-order the collection variableProperties = variableProperties.OrderBy(p => p.Position).ToList(); // Subtract position to stay on the same spot for subsequent property iCurrentProperty--; } else { // Create a list of features. FeatureExt = new TDSLogin7FeatureOptionsToken(); // Inflate feature extension FeatureExt.Inflate(source); // Advance position by the size of the inflated token inflationOffset += FeatureExt.InflationSize; } } else { // Read the string and assign it to the property of this instance property.Property.SetValue(this, TDSUtilities.ReadString(source, (ushort)(property.Length * 2)), null); // Advance the position inflationOffset += (property.Length * 2); } // Advance to the next property iCurrentProperty++; } return(true); }
/// <summary> /// Deflate the token /// </summary> /// <param name="destination">Stream to deflate token to</param> public override void Deflate(Stream destination) { // Calculate total length by adding strings uint totalPacketLength = (uint)(FixedPacketLength + (uint)(string.IsNullOrEmpty(HostName) ? 0 : HostName.Length * 2) // HostName + (uint)(string.IsNullOrEmpty(UserID) ? 0 : UserID.Length * 2) // UserID + (uint)(string.IsNullOrEmpty(Password) ? 0 : Password.Length * 2) // Password + (uint)(string.IsNullOrEmpty(ApplicationName) ? 0 : ApplicationName.Length * 2) // ApplicationName + (uint)(string.IsNullOrEmpty(ServerName) ? 0 : ServerName.Length * 2) // ServerName + (uint)(string.IsNullOrEmpty(LibraryName) ? 0 : LibraryName.Length * 2) // LibraryName + (uint)(string.IsNullOrEmpty(Language) ? 0 : Language.Length * 2) // Language + (uint)(string.IsNullOrEmpty(Database) ? 0 : Database.Length * 2) // Database + (uint)(string.IsNullOrEmpty(AttachDatabaseFile) ? 0 : AttachDatabaseFile.Length * 2) // AttachDatabaseFile + (uint)(string.IsNullOrEmpty(ChangePassword) ? 0 : ChangePassword.Length * 2) // ChangePassword + (uint)(SSPI == null ? 0 : SSPI.Length) // SSPI + 0); // Feature extension MemoryStream featureExtension = null; // Check if we have a feature extension if (FeatureExt != null) { // Allocate feature extension block featureExtension = new MemoryStream(); // Serialize feature extension FeatureExt.Deflate(featureExtension); // Update total lentgh totalPacketLength += (uint)(sizeof(uint) /* Offset of feature extension data */ + featureExtension.Length /* feature extension itself*/); } // Write packet length TDSUtilities.WriteUInt(destination, totalPacketLength); // Compile TDS version uint tdsVersion = Convert.ToUInt32(string.Format("{0:X}", Math.Max(TDSVersion.Major, 0)) + string.Format("{0:X}", Math.Max(TDSVersion.Minor, 0)) + string.Format("{0:X2}", Math.Max(TDSVersion.Build, 0)) + string.Format("{0:X4}", Math.Max(TDSVersion.Revision, 0)), 16); // Write TDS version TDSUtilities.WriteUInt(destination, tdsVersion); // Write packet length TDSUtilities.WriteUInt(destination, PacketSize); // Write client program version TDSUtilities.WriteUInt(destination, ClientProgramVersion); // Write client program identifier TDSUtilities.WriteUInt(destination, ClientPID); // Write connection identifier TDSUtilities.WriteUInt(destination, ConnectionID); // Write the first optional flags destination.WriteByte(OptionalFlags1.ToByte()); // Write the second optional flags destination.WriteByte(OptionalFlags2.ToByte()); // Instantiate type flags destination.WriteByte(TypeFlags.ToByte()); // Write the third optional flags destination.WriteByte(OptionalFlags3.ToByte()); // Write client time zone TDSUtilities.WriteInt(destination, ClientTimeZone); // Write client locale identifier TDSUtilities.WriteUInt(destination, ClientLCID); // Prepare a collection of property values that will be set later IList <TDSLogin7TokenOffsetProperty> variableProperties = new List <TDSLogin7TokenOffsetProperty>(); // Write client host name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("HostName"), FixedPacketLength, (ushort)(string.IsNullOrEmpty(HostName) ? 0 : HostName.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write user name and password variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("UserID"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(UserID) ? 0 : UserID.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Password"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(Password) ? 0 : Password.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write application name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ApplicationName"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(ApplicationName) ? 0 : ApplicationName.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write server name variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ServerName"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(ServerName) ? 0 : ServerName.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Check if we have a feature extension block if (FeatureExt != null) { // Write the offset of the feature extension offset (pointer to pointer) variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("FeatureExt"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), sizeof(uint) / 2, true)); // Should be 4 bytes, devided by 2 because the next guy multiplies by 2 TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)(variableProperties.Last().Length * 2)); // Compensate for division by 2 above } else { // Skip unused TDSUtilities.WriteUShort(destination, 0); TDSUtilities.WriteUShort(destination, 0); } // Write client library name // We do not need to account for skipped unused bytes here because they're already accounted in fixedPacketLength variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("LibraryName"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(LibraryName) ? 0 : LibraryName.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write language variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Language"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(Language) ? 0 : Language.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write database variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("Database"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(Database) ? 0 : Database.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Check if client is defined if (ClientID == null) { // Allocate empty identifier ClientID = new byte[6]; } // Write unique client identifier destination.Write(ClientID, 0, 6); // Write SSPI variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("SSPI"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(SSPI == null ? 0 : SSPI.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write database file to be attached. NOTE, "variableProperties.Last().Length" without " * 2" because the preceeding buffer isn't string variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("AttachDatabaseFile"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length), (ushort)(string.IsNullOrEmpty(AttachDatabaseFile) ? 0 : AttachDatabaseFile.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Write password change variableProperties.Add(new TDSLogin7TokenOffsetProperty(GetType().GetProperty("ChangePassword"), (ushort)(variableProperties.Last().Position + variableProperties.Last().Length * 2), (ushort)(string.IsNullOrEmpty(ChangePassword) ? 0 : ChangePassword.Length))); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Position); TDSUtilities.WriteUShort(destination, (ushort)variableProperties.Last().Length); // Skip long SSPI TDSUtilities.WriteUInt(destination, 0); // We will be changing collection as we go and serialize everything. As such we can't use foreach and iterator. int iCurrentProperty = 0; // Iterate through the collection while (iCurrentProperty < variableProperties.Count) { // Get current property by index TDSLogin7TokenOffsetProperty property = variableProperties[iCurrentProperty]; // Check if length is positive if (property.Length == 0) { // Move to the next property iCurrentProperty++; continue; } // Check special properties if (property.Property.Name == "Password" || property.Property.Name == "ChangePassword") { // Write encrypted string value TDSUtilities.WritePasswordString(destination, (string)property.Property.GetValue(this, null)); } else if (property.Property.Name == "FeatureExt") { // Check if we are to serialize the offset or the actual data if (property.IsOffsetOffset) { // Property will be written at the offset immediately following all variable length data property.Position = variableProperties.Last().Position + variableProperties.Last().Length; // Write the position at which we'll be serializing the feature extension block TDSUtilities.WriteUInt(destination, property.Position); // Order strings in ascending order by offset variableProperties = variableProperties.OrderBy(p => p.Position).ToList(); // Compensate increment to the next position in order to stay on the same iCurrentProperty--; // No longer offset, actual data is going to follow property.IsOffsetOffset = false; } else { // Transfer deflated feature extension into the login stream featureExtension.WriteTo(destination); } } else if (property.Property.Name == "SSPI") { // Write SSPI destination.Write(SSPI, 0, SSPI.Length); } else { // Write the string value TDSUtilities.WriteString(destination, (string)property.Property.GetValue(this, null)); } // Move to the next property iCurrentProperty++; } }
/// <summary> /// Deflate the token /// </summary> /// <param name="destination">Stream to deflate token to</param> public override void Deflate(Stream destination) { // Allocate stream for token data // We need to cache it to calculate the environment change token length MemoryStream cache = new MemoryStream(); // Write environment change type cache.WriteByte((byte)Type); // Write the rest of the token based on the token type switch (Type) { case TDSEnvChangeTokenType.Database: case TDSEnvChangeTokenType.Language: case TDSEnvChangeTokenType.CharacterSet: case TDSEnvChangeTokenType.PacketSize: case TDSEnvChangeTokenType.RealTimeLogShipping: { // Write new value length cache.WriteByte((byte)(string.IsNullOrEmpty((string)NewValue) ? 0 : ((string)NewValue).Length)); // Write new value TDSUtilities.WriteString(cache, (string)NewValue); // Write old value length cache.WriteByte((byte)(string.IsNullOrEmpty((string)OldValue) ? 0 : ((string)OldValue).Length)); // Write old value TDSUtilities.WriteString(cache, (string)OldValue); break; } case TDSEnvChangeTokenType.Routing: { // Create a sub-cache to determine the value length MemoryStream subCache = new MemoryStream(); // Check if new value exists if (NewValue != null) { // Deflate token value (NewValue as TDSRoutingEnvChangeTokenValue).Deflate(subCache); } // Write new value length TDSUtilities.WriteUShort(cache, (ushort)subCache.Length); // Write new value subCache.WriteTo(cache); // Write zero for the old value length TDSUtilities.WriteUShort(cache, 0); break; } case TDSEnvChangeTokenType.SQLCollation: { // Write new value length cache.WriteByte((byte)(NewValue != null ? ((byte[])NewValue).Length : 0)); // Check if we have a new value if (NewValue != null) { // Write new value cache.Write((byte[])NewValue, 0, ((byte[])NewValue).Length); } // Write old value length cache.WriteByte((byte)(OldValue != null ? ((byte[])OldValue).Length : 0)); // Check if we have a old value if (OldValue != null) { // Write old value cache.Write((byte[])OldValue, 0, ((byte[])OldValue).Length); } break; } case TDSEnvChangeTokenType.BeginTransaction: { // Write new value length cache.WriteByte((byte)(NewValue != null ? ((byte[])NewValue).Length : 0)); // Check if we have a new value if (NewValue != null) { // Write new value cache.Write((byte[])NewValue, 0, ((byte[])NewValue).Length); } cache.WriteByte(0); break; } case TDSEnvChangeTokenType.CommitTransaction: { // Write new value length cache.WriteByte(0); cache.WriteByte((byte)(OldValue != null ? ((byte[])OldValue).Length : 0)); // Check if we have a new value if (OldValue != null) { // Write new value cache.Write((byte[])OldValue, 0, ((byte[])OldValue).Length); } break; } default: { throw new Exception("Unrecognized environment change type"); } } // Write token identifier destination.WriteByte((byte)TDSTokenType.EnvironmentChange); // Write length TDSUtilities.WriteUShort(destination, (ushort)cache.Length); // Write token data cache.WriteTo(destination); }
/// <summary> /// Inflate the token /// NOTE: This operation is not continuable and assumes that the entire token is available in the stream /// </summary> /// <param name="source">Stream to inflate the token from</param> /// <returns>TRUE if inflation is complete</returns> public override bool Inflate(Stream source) { // We skip the token identifier because it is read by token factory // Read token length ushort tokenLength = TDSUtilities.ReadUShort(source); // Check if length can accomodate at least the type if (tokenLength == 0) { // We're done inflating this token return(true); } // Read the token type Type = (TDSEnvChangeTokenType)source.ReadByte(); // Update the token length left tokenLength--; // Check if we can squeez anything else if (tokenLength == 0) { // We're done inflating this token return(true); } // Read the rest of the token based on the token type switch (Type) { case TDSEnvChangeTokenType.Database: case TDSEnvChangeTokenType.Language: case TDSEnvChangeTokenType.CharacterSet: case TDSEnvChangeTokenType.PacketSize: case TDSEnvChangeTokenType.RealTimeLogShipping: { // Read new value length byte valueLength = (byte)source.ReadByte(); // Update token length tokenLength--; // Read string of the specified size NewValue = TDSUtilities.ReadString(source, (ushort)(valueLength * 2)); // Update token length tokenLength -= (ushort)(valueLength * 2); // Check if old value can fit in if (tokenLength == 0) { // Old value won't fit in break; } // Read old value length valueLength = (byte)source.ReadByte(); // Update token length tokenLength--; // Read string of the specified size OldValue = TDSUtilities.ReadString(source, (ushort)(valueLength * 2)); // Update token length tokenLength -= (ushort)(valueLength * 2); // Inflation is complete break; } case TDSEnvChangeTokenType.Routing: { // Read the new value length ushort valueLength = TDSUtilities.ReadUShort(source); // Update token length tokenLength -= 2; // sizeof(ushort) // Instantiate new value NewValue = new TDSRoutingEnvChangeTokenValue(); // Inflate new value if (!(NewValue as TDSRoutingEnvChangeTokenValue).Inflate(source)) { // We should never reach this point throw new Exception("Routing information inflation failed"); } // Read always-zero old value unsigned short if (TDSUtilities.ReadUShort(source) != 0) { // We should never reach this point throw new Exception("Non-zero old value for routing information"); } break; } case TDSEnvChangeTokenType.SQLCollation: { // Read new value length byte valueLength = (byte)source.ReadByte(); // Update token length tokenLength--; // Check if old value can fit in if (tokenLength == 0) { // Old value won't fit in break; } // Allocate the buffer byte[] byteValue = new byte[valueLength]; // Read bytes off the wire source.Read(byteValue, 0, byteValue.Length); // Set new value NewValue = byteValue; // Update token length tokenLength -= valueLength; // Check if old value can fit in if (tokenLength == 0) { // Old value won't fit in break; } // Read old value length valueLength = (byte)source.ReadByte(); // Update token length tokenLength--; // Check if old value can fit in if (tokenLength == 0) { // Old value won't fit in break; } // Allocate the buffer byteValue = new byte[valueLength]; // Read bytes off the wire source.Read(byteValue, 0, byteValue.Length); // Set old value OldValue = byteValue; // Update token length tokenLength -= valueLength; // Inflation is complete break; } default: { // Skip the rest of the token byte[] tokenData = new byte[tokenLength]; source.Read(tokenData, 0, tokenData.Length); break; } } return(true); }
/// <summary> /// Handler for login request /// </summary> public virtual TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Log request TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Update server context session.Database = string.IsNullOrEmpty(loginRequest.Database) ? "master" : loginRequest.Database; // Resolve TDS version session.TDSVersion = TDSVersion.Resolve(TDSVersion.GetTDSVersion(Arguments.ServerVersion), loginRequest.TDSVersion); // Check for the TDS version TDSMessageCollection collection = CheckTDSVersion(session); // Check if any errors are posted if (collection != null) { // Version check needs to send own message hence we can't proceed return(collection); } // Indicates federated authentication bool bIsFedAuthConnection = false; // Federated authentication option to be used later TDSLogin7FedAuthOptionToken federatedAuthenticationOption = null; // Check if feature extension block is available if (loginRequest.FeatureExt != null) { // Go over the feature extension data foreach (TDSLogin7FeatureOptionToken option in loginRequest.FeatureExt) { // Check option type switch (option.FeatureID) { case TDSFeatureID.SessionRecovery: { // Enable session recovery session.IsSessionRecoveryEnabled = true; // Cast to session state options TDSLogin7SessionRecoveryOptionToken sessionStateOption = option as TDSLogin7SessionRecoveryOptionToken; // Inflate session state (session as GenericTDSServerSession).Inflate(sessionStateOption.Initial, sessionStateOption.Current); break; } case TDSFeatureID.FederatedAuthentication: { // Cast to federated authentication option federatedAuthenticationOption = option as TDSLogin7FedAuthOptionToken; // Mark authentication as federated bIsFedAuthConnection = true; // Validate federated authentication option collection = CheckFederatedAuthenticationOption(session, option as TDSLogin7FedAuthOptionToken); if (collection != null) { // Version error happened. return(collection); } // Save the fed auth library to be used (session as GenericTDSServerSession).FederatedAuthenticationLibrary = federatedAuthenticationOption.Library; break; } default: { // Do nothing break; } } } } // Check if SSPI authentication is requested if (loginRequest.OptionalFlags2.IntegratedSecurity == TDSLogin7OptionalFlags2IntSecurity.On) { // Delegate to SSPI authentication return(ContinueSSPIAuthentication(session, loginRequest.SSPI)); } // If it is not a FedAuth connection or the server has been started up as not supporting FedAuth, just ignore the FeatureExtension // Yes unfortunately for the fake server, supporting FedAuth = Requiring FedAuth if (!bIsFedAuthConnection || Arguments.FedAuthRequiredPreLoginOption == TdsPreLoginFedAuthRequiredOption.FedAuthNotRequired) { // We use SQL authentication session.SQLUserID = loginRequest.UserID; // Process with the SQL login. return(OnSqlAuthenticationCompleted(session)); } else { // Fedauth feature extension is present and server has been started up as Requiring (or Supporting) FedAuth if (federatedAuthenticationOption.IsRequestingAuthenticationInfo) { // Must provide client with more info before completing authentication return(OnFederatedAuthenticationInfoRequest(session)); } else { return(OnFederatedAuthenticationCompleted(session, federatedAuthenticationOption.Token)); } } }
/// <summary> /// Deflate the token /// </summary> /// <param name="destination">Stream to deflate token to</param> public void Deflate(Stream destination) { // Write user type TDSUtilities.WriteUInt(destination, UserType); // Convert flags to value and write them TDSUtilities.WriteUShort(destination, Flags.ToUShort()); // Write type destination.WriteByte((byte)DataType); // Dispatch further writing based on the type switch (DataType) { case TDSDataType.Binary: case TDSDataType.VarBinary: case TDSDataType.Char: case TDSDataType.VarChar: case TDSDataType.BitN: case TDSDataType.Guid: case TDSDataType.IntN: case TDSDataType.MoneyN: case TDSDataType.FloatN: case TDSDataType.DateTimeN: { // Byte length destination.WriteByte((byte)DataTypeSpecific); break; } case TDSDataType.DateN: { // No details break; } case TDSDataType.TimeN: case TDSDataType.DateTime2N: case TDSDataType.DateTimeOffsetN: { // Scale destination.WriteByte((byte)DataTypeSpecific); break; } case TDSDataType.DecimalN: case TDSDataType.NumericN: { // Cast to type-specific information TDSDecimalColumnSpecific typeSpecific = DataTypeSpecific as TDSDecimalColumnSpecific; // Write values destination.WriteByte(typeSpecific.Length); destination.WriteByte(typeSpecific.Precision); destination.WriteByte(typeSpecific.Scale); break; } case TDSDataType.BigBinary: case TDSDataType.BigVarBinary: { // Short length TDSUtilities.WriteUShort(destination, (ushort)DataTypeSpecific); break; } case TDSDataType.BigChar: case TDSDataType.BigVarChar: case TDSDataType.NChar: case TDSDataType.NVarChar: { // Cast to type specific information TDSShilohVarCharColumnSpecific typedSpecific = DataTypeSpecific as TDSShilohVarCharColumnSpecific; // Write length TDSUtilities.WriteUShort(destination, typedSpecific.Length); // Write collation TDSUtilities.WriteUInt(destination, typedSpecific.Collation.WCID); destination.WriteByte(typedSpecific.Collation.SortID); break; } case TDSDataType.Text: case TDSDataType.NText: { // YukonTextType.Len + YukonTextType.tdsCollationInfo + YukonTextType.cParts // cb = sizeof(LONG) + sizeof(TDSCOLLATION) + sizeof(BYTE); break; } case TDSDataType.Image: { // Integer length TDSUtilities.WriteUInt(destination, (uint)DataTypeSpecific); break; } case TDSDataType.SSVariant: { // Data length TDSUtilities.WriteUInt(destination, (uint)DataTypeSpecific); break; } case TDSDataType.Udt: { // hr = GetUDTColFmt(pvOwner, dwTimeout); break; } case TDSDataType.Xml: { // cb = sizeof(lpColFmt->YukonXmlType.bSchemaPresent); break; } } // Check if we need to write table name if ((DataType == TDSDataType.Text || DataType == TDSDataType.NText || DataType == TDSDataType.Image) && (TableName != null)) { // Write part count destination.WriteByte((byte)TableName.Count); // Write each part foreach (string part in TableName) { // Write table part length TDSUtilities.WriteUShort(destination, (ushort)(string.IsNullOrEmpty(part) ? 0 : part.Length)); // Write table part TDSUtilities.WriteString(destination, part); } } // Write column name length destination.WriteByte((byte)(string.IsNullOrEmpty(Name) ? 0 : Name.Length)); // Write column name TDSUtilities.WriteString(destination, Name); }
/// <summary> /// Complete the Federated Login /// </summary> /// <param name="session">Server session</param> /// <returns>Federated Login message collection</returns> protected virtual TDSMessageCollection OnFederatedAuthenticationCompleted(ITDSServerSession session, byte[] ticket) { // Delegate to successful authentication routine TDSMessageCollection responseMessageCollection = OnAuthenticationCompleted(session); // Get the last message TDSMessage targetMessage = responseMessageCollection.Last(); IFederatedAuthenticationTicket decryptedTicket = null; try { // Get the Federated Authentication ticket using RPS decryptedTicket = FederatedAuthenticationTicketService.DecryptTicket((session as GenericTDSServerSession).FederatedAuthenticationLibrary, ticket); if (decryptedTicket is RpsTicket) { TDSUtilities.Log(Arguments.Log, "RPS ticket session key: ", (decryptedTicket as RpsTicket).sessionKey); } else if (decryptedTicket is JwtTicket) { TDSUtilities.Log(Arguments.Log, "JWT Ticket Received", null); } } catch (Exception ex) { // Prepare ERROR token TDSErrorToken errorToken = new TDSErrorToken(54879, 1, 20, "Authentication error in Federated Authentication Ticket Service: " + ex.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Return the message and stop processing request return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, errorToken, doneToken))); } // Create federated authentication extension option TDSFeatureExtAckFederatedAuthenticationOption federatedAuthenticationOption; if ((session as GenericTDSServerSession).FederatedAuthenticationLibrary == TDSFedAuthLibraryType.ADAL) { // For the time being, fake fedauth tokens are used for ADAL, so decryptedTicket is null. federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, null); } else { federatedAuthenticationOption = new TDSFeatureExtAckFederatedAuthenticationOption((session as GenericTDSServerSession).ClientNonce, decryptedTicket.GetSignature((session as GenericTDSServerSession).ClientNonce)); } // Look for feature extension token TDSFeatureExtAckToken featureExtActToken = (TDSFeatureExtAckToken)targetMessage.Where(t => t is TDSFeatureExtAckToken).FirstOrDefault(); // Check if response already contains federated authentication if (featureExtActToken == null) { // Create Feature extension Ack token featureExtActToken = new TDSFeatureExtAckToken(federatedAuthenticationOption); // Serialize feature extension token into the response // The last token is Done token, so we should put feautureextack token before done token targetMessage.Insert(targetMessage.Count - 1, featureExtActToken); } else { // Update featureExtActToken.Options.Add(federatedAuthenticationOption); } // Log response TDSUtilities.Log(Arguments.Log, "Response", federatedAuthenticationOption); // Wrap a message with a collection return(responseMessageCollection); }
public override bool Inflate(Stream source) { var len = source.ReadByte(); if (len == -1) { return(false); } ParamMetaData = TDSUtilities.ReadString(source, (ushort)(len * 2)); StatusFlags = new TDSRPCRequestStatusFlags((byte)source.ReadByte()); DataType = (TDSDataType)source.ReadByte(); // Dispatch further reading based on the type switch (DataType) { case TDSDataType.Binary: case TDSDataType.VarBinary: case TDSDataType.Char: case TDSDataType.VarChar: // The above types are deprecated after TDS 7205. case TDSDataType.BitN: case TDSDataType.Guid: case TDSDataType.IntN: case TDSDataType.MoneyN: case TDSDataType.FloatN: case TDSDataType.DateTimeN: { // Byte length DataTypeSpecific = source.ReadByte(); break; } case TDSDataType.DateN: { // No details DataTypeSpecific = null; break; } case TDSDataType.TimeN: case TDSDataType.DateTime2N: case TDSDataType.DateTimeOffsetN: { // Scale DataTypeSpecific = source.ReadByte(); break; } case TDSDataType.DecimalN: case TDSDataType.NumericN: { // Read values byte length = (byte)source.ReadByte(); byte precision = (byte)source.ReadByte(); byte scale = (byte)source.ReadByte(); // Decimal data type specific DataTypeSpecific = new TDSDecimalColumnSpecific(length, precision, scale); break; } case TDSDataType.BigBinary: case TDSDataType.BigVarBinary: { // Short length DataTypeSpecific = TDSUtilities.ReadUShort(source); break; } case TDSDataType.BigChar: case TDSDataType.BigVarChar: case TDSDataType.NChar: case TDSDataType.NVarChar: { // SHILOH CHAR types have collation associated with it. TDSShilohVarCharColumnSpecific typedSpecific = new TDSShilohVarCharColumnSpecific(); // Read length typedSpecific.Length = TDSUtilities.ReadUShort(source); // Create collation typedSpecific.Collation = new TDSColumnDataCollation(); // Read collation typedSpecific.Collation.WCID = TDSUtilities.ReadUInt(source); typedSpecific.Collation.SortID = (byte)source.ReadByte(); DataTypeSpecific = typedSpecific; break; } case TDSDataType.Text: case TDSDataType.NText: { // YukonTextType.Len + YukonTextType.tdsCollationInfo + YukonTextType.cParts // cb = sizeof(LONG) + sizeof(TDSCOLLATION) + sizeof(BYTE); break; } case TDSDataType.Image: { // Data length DataTypeSpecific = TDSUtilities.ReadUInt(source); break; } case TDSDataType.SSVariant: { // Data length DataTypeSpecific = TDSUtilities.ReadUInt(source); break; } case TDSDataType.Udt: { // hr = GetUDTColFmt(pvOwner, dwTimeout); break; } case TDSDataType.Xml: { // cb = sizeof(lpColFmt->YukonXmlType.bSchemaPresent); break; } } Value = TDSRowTokenBase.InflateColumnData(source, DataType, DataTypeSpecific); return(true); }
/// <summary> /// Inflate from stream /// </summary> public virtual bool Inflate(Stream source) { // Create options collection Options = new List <TDSSessionStateOption>(); // Current position in the stream InflationSize = 0; // Read the total length uint totalLength = TDSUtilities.ReadUInt(source); // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } // Read the length of the string byte byteLength = (byte)source.ReadByte(); // Update offset InflationSize += sizeof(byte); // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } // Read the string Database = TDSUtilities.ReadString(source, (ushort)(byteLength * 2)); // Update offset InflationSize += ((uint)byteLength * 2); // one character is 2 bytes long // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } // Read the length of the collation byteLength = (byte)source.ReadByte(); // Update offset InflationSize += sizeof(byte); // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } // Check if we have a collation if (byteLength > 0) { // Allocate collation Collation = new byte[5]; // Read collation int readBytes = source.Read(Collation, 0, Collation.Length); // Update offset InflationSize += (uint)readBytes; // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } } // Read the length of the string byteLength = (byte)source.ReadByte(); // Update offset InflationSize += sizeof(byte); // Check if we still have space to read if (InflationSize >= totalLength) { // Inflation is complete return(true); } // Read the string Language = TDSUtilities.ReadString(source, (ushort)(byteLength * 2)); // Update offset InflationSize += ((uint)byteLength * 2); // one character is 2 bytes long // Read while we have data while (totalLength > InflationSize) { // Read a byte that identifies the session state slot byte stateID = (byte)source.ReadByte(); // Update current position InflationSize += sizeof(byte); // Option being inflated TDSSessionStateOption option = null; // Dispatch inflation based on the state switch (stateID) { // UserOptionAll case TDSSessionStateUserOptionsOption.ID: { // Create a new option option = new TDSSessionStateUserOptionsOption(); break; } // DateFirstDateFormat case TDSSessionStateDateFirstDateFormatOption.ID: { // Create a new option option = new TDSSessionStateDateFirstDateFormatOption(); break; } // DbDeadlockPri case TDSSessionStateDeadlockPriorityOption.ID: { // Create a new option option = new TDSSessionStateDeadlockPriorityOption(); break; } // LockTimeout case TDSSessionStateLockTimeoutOption.ID: { // Create a new option option = new TDSSessionStateLockTimeoutOption(); break; } // IsoFips case TDSSessionStateISOFipsOption.ID: { // Create a new option option = new TDSSessionStateISOFipsOption(); break; } // TextSize case TDSSessionStateTextSizeOption.ID: { // Create a new option option = new TDSSessionStateTextSizeOption(); break; } // ContextInfo case TDSSessionStateContextInfoOption.ID: { // Create a new option option = new TDSSessionStateContextInfoOption(); break; } default: { // Create a new option option = new TDSSessionStateGenericOption(stateID); break; } } // Inflate the option option.Inflate(source); // Register option with the collection Options.Add(option); // Update current length with the inflation size of the data InflationSize += option.InflationSize; } // Inflation is complete return(true); }
protected virtual TDSMessageCollection OnAuthenticationCompleted(ITDSServerSession session) { // Create new database environment change token TDSEnvChangeToken envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Database, session.Database, "master"); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, envChange); // Create information token on the change TDSInfoToken infoToken = new TDSInfoToken(5701, 2, 0, string.Format("Changed database context to '{0}'", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new collation change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.SQLCollation, (session as GenericTDSServerSession).Collation); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create new language change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.Language, LanguageString.ToString((session as GenericTDSServerSession).Language)); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Create information token on the change infoToken = new TDSInfoToken(5703, 1, 0, string.Format("Changed language setting to {0}", envChange.NewValue), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", infoToken); // Serialize the login token into the response packet responseMessage.Add(infoToken); // Create new packet size environment change token envChange = new TDSEnvChangeToken(TDSEnvChangeTokenType.PacketSize, Arguments.PacketSize.ToString(), Arguments.PacketSize.ToString()); // Log response TDSUtilities.Log(Arguments.Log, "Response", envChange); // Serialize the login token into the response packet responseMessage.Add(envChange); // Update session packet size session.PacketSize = (uint)Arguments.PacketSize; // Create login acknowledgnment packet TDSLoginAckToken loginResponseToken = new TDSLoginAckToken(Arguments.ServerVersion, session.TDSVersion, TDSLogin7TypeFlagsSQL.SQL, "Microsoft SQL Server"); // Otherwise SNAC yields E_FAIL // Log response TDSUtilities.Log(Arguments.Log, "Response", loginResponseToken); // Serialize the login token into the response packet responseMessage.Add(loginResponseToken); // Check if session recovery is enabled if (session.IsSessionRecoveryEnabled) { // Create Feature extension Ack token TDSFeatureExtAckToken featureExtActToken = new TDSFeatureExtAckToken(new TDSFeatureExtAckSessionStateOption((session as GenericTDSServerSession).Deflate())); // Log response TDSUtilities.Log(Arguments.Log, "Response", featureExtActToken); // Serialize feature extnesion token into the response responseMessage.Add(featureExtActToken); } // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Wrap a single message in a collection return(new TDSMessageCollection(responseMessage)); }
/// <summary> /// Inflate a particular column from the stream /// </summary> /// <param name="source">Stream to inflate the column from</param> /// <param name="column">Metadata about the column</param> /// <returns>TRUE if inflation is complete</returns> protected virtual object InflateColumn(Stream source, TDSColumnData column) { // Dispatch further reading based on the type switch (column.DataType) { case TDSDataType.Null: { // No data associated with it return(null); } case TDSDataType.Bit: case TDSDataType.Int1: { // Bit, 1 byte data representation return((byte)source.ReadByte()); } case TDSDataType.Int2: { // SmallInt, 2 byte data representation return(unchecked ((short)TDSUtilities.ReadUShort(source))); } case TDSDataType.Int4: { // Int, 4 byte data representation return(unchecked ((int)TDSUtilities.ReadUInt(source))); } case TDSDataType.Float8: { // Float (8 byte data representation) return(BitConverter.ToDouble(BitConverter.GetBytes(TDSUtilities.ReadULong(source)), 0)); } case TDSDataType.Int8: { // BigInt (8 byte data representation) return(unchecked ((long)TDSUtilities.ReadULong(source))); } case TDSDataType.BitN: { // Read length byte length = (byte)source.ReadByte(); // Check if null if (length == 0) { // No data return(null); } // Bit, 1 byte data representation return((byte)source.ReadByte()); } case TDSDataType.IntN: { // Read length byte length = (byte)source.ReadByte(); // Check integer length switch (length) { case 0: { // No data return(null); } case 1: { // Bit data return((byte)source.ReadByte()); } case 2: { // Short data return(unchecked ((short)TDSUtilities.ReadUShort(source))); } case 4: { // Integer data return(unchecked ((int)TDSUtilities.ReadUInt(source))); } case 8: { // Integer data return(unchecked ((long)TDSUtilities.ReadULong(source))); } default: { // We don't know how to inflate this integer throw new InvalidDataException(string.Format("Unable to inflate integer of {0} bytes", length)); } } } case TDSDataType.NumericN: { // Read length byte length = (byte)source.ReadByte(); // Check if null if (length == 0) { // No data return(null); } // Allocate value container byte[] guidBytes = new byte[length]; // Read value source.Read(guidBytes, 0, guidBytes.Length); // Instantiate type return(guidBytes); } case TDSDataType.Guid: { // Read the length byte length = (byte)source.ReadByte(); // Check if we have any data if (length == 0x0000) { // No data return(null); } // Allocate value container byte[] guidBytes = new byte[length]; // Read value source.Read(guidBytes, 0, guidBytes.Length); // Convert to type return(new Guid(guidBytes)); } case TDSDataType.BigVarChar: case TDSDataType.BigChar: { // Read length ushort length = TDSUtilities.ReadUShort(source); // Check if we have any data if (length == 0xFFFF) { // No data return(null); } // Allocate value container byte[] textBytes = new byte[length]; // Read value source.Read(textBytes, 0, textBytes.Length); // Convert to type return(Encoding.ASCII.GetString(textBytes)); } case TDSDataType.NVarChar: { // Check if MAX type if ((column.DataTypeSpecific as TDSShilohVarCharColumnSpecific).Length == 0xFFFF) { // Read the length of partialy length-prefixed type ulong length = TDSUtilities.ReadULong(source); // Check the value if (length == 0xFFFFFFFFFFFFFFFF) { // There's no data return(null); } else if (length == 0xFFFFFFFFFFFFFFFE) { throw new NotImplementedException("UNKNOWN_PLP_LEN is not implemented yet"); } else { // Allocate a memory stream MemoryStream chunks = new MemoryStream(); // Size of the last chunk uint chunkLength = 0; // Iterate until we read the whole data do { // Read the length of the chunk chunkLength = TDSUtilities.ReadUInt(source); // Allocate chunk container byte[] chunk = new byte[chunkLength]; // Read value source.Read(chunk, 0, chunk.Length); // Append into the stream chunks.Write(chunk, 0, chunk.Length); }while (chunkLength > 0); // Convert to byte array byte[] byteString = chunks.ToArray(); // Serialize the data into the string return(Encoding.Unicode.GetString(byteString, 0, byteString.Length)); } } else { // Read length ushort length = TDSUtilities.ReadUShort(source); // Check if we have any data if (length == 0xFFFF) { // No data return(null); } // Read the whole string at once return(TDSUtilities.ReadString(source, (ushort)length)); } } case TDSDataType.BigVarBinary: { byte[] bytes = null; // Check if MAX type if ((ushort)column.DataTypeSpecific == 0xFFFF) { // Read the length of partialy length-prefixed type ulong length = TDSUtilities.ReadULong(source); // Check the value if (length == 0xFFFFFFFFFFFFFFFF) { // There's no data return(null); } else if (length == 0xFFFFFFFFFFFFFFFE) { throw new NotImplementedException("UNKNOWN_PLP_LEN is not implemented yet"); } else { // Allocate a memory stream MemoryStream chunks = new MemoryStream(); // Size of the last chunk uint chunkLength = 0; // Iterate until we read the whole data do { // Read the length of the chunk chunkLength = TDSUtilities.ReadUInt(source); // Allocate chunk container byte[] chunk = new byte[chunkLength]; // Read value source.Read(chunk, 0, chunk.Length); // Append into the stream chunks.Write(chunk, 0, chunk.Length); }while (chunkLength > 0); // Serialize to byte array bytes = chunks.ToArray(); } } else { // Read length ushort length = TDSUtilities.ReadUShort(source); // Check if we have any data if (length == 0xFFFF) { // No data return(null); } // Allocate value container bytes = new byte[length]; // Read value source.Read(bytes, 0, bytes.Length); } // Convert to type return(bytes); } case TDSDataType.BigBinary: { // Read length ushort length = TDSUtilities.ReadUShort(source); // Check if we have any data if (length == 0xFFFF) { // No data return(null); } // Allocate value container byte[] bytes = new byte[length]; // Read value source.Read(bytes, 0, bytes.Length); // Convert to type return(bytes); } default: { // We don't know this type throw new NotImplementedException(string.Format("Unrecognized data type {0} for inflation", column.DataType)); } } }
/// <summary> /// Deflate the column into the stream /// </summary> /// <param name="destination">Stream to deflate token to</param> /// <param name="column">Column metadata</param> /// <param name="data">Column value</param> protected virtual void DeflateColumn(Stream destination, TDSColumnData column, object data) { // Dispatch further reading based on the type switch (column.DataType) { case TDSDataType.Null: { // No data associated with it break; } case TDSDataType.Bit: { destination.WriteByte((byte)((bool)data ? 1 : 0)); break; } case TDSDataType.Int1: { // Bit, 1 byte data representation destination.WriteByte((byte)data); break; } case TDSDataType.Int2: { // SmallInt, 2 byte data representation TDSUtilities.WriteUShort(destination, unchecked ((ushort)((short)data))); break; } case TDSDataType.Int4: { // Int, 4 byte data representation TDSUtilities.WriteUInt(destination, unchecked ((uint)((int)data))); break; } case TDSDataType.Float8: { // Float (8 byte data representation) byte[] floatBytes = BitConverter.GetBytes((double)data); destination.Write(floatBytes, 0, floatBytes.Length); break; } case TDSDataType.Int8: { // BigInt (8 byte data representation) TDSUtilities.WriteULong(destination, unchecked ((ulong)((long)data))); break; } case TDSDataType.BitN: { // Check if data is available if (data == null) { // No data destination.WriteByte(0); } else { // One byte data destination.WriteByte(1); // Data destination.WriteByte((byte)((bool)data ? 1 : 0)); } break; } case TDSDataType.IntN: { // Check if data is available if (data == null) { // No data destination.WriteByte(0); } else if (data is byte) { // One-byte data destination.WriteByte(1); // Bit data destination.WriteByte((byte)data); } else if (data is short) { // One-byte data destination.WriteByte(2); // Short data TDSUtilities.WriteUShort(destination, unchecked ((ushort)(short)data)); } else if (data is int) { // One-byte data destination.WriteByte(4); // Integer data TDSUtilities.WriteUInt(destination, unchecked ((uint)(int)data)); } else if (data is long) { // One-byte data destination.WriteByte(8); // Long data TDSUtilities.WriteULong(destination, unchecked ((ulong)(long)data)); } else { // We don't know how to deflate this integer throw new InvalidDataException(string.Format("Unable to deflate integer of type {0}", data.GetType().FullName)); } break; } case TDSDataType.Guid: { // Check if data is available if (data == null) { // No data destination.WriteByte(0); } else { // Get bytes byte[] guidBytes = ((Guid)data).ToByteArray(); // One byte data length destination.WriteByte((byte)guidBytes.Length); // Data destination.Write(guidBytes, 0, guidBytes.Length); } break; } case TDSDataType.BigChar: case TDSDataType.BigVarChar: { // Check if data is available if (data == null) { // No data TDSUtilities.WriteUShort(destination, 0xFFFF); } else { // Get bytes byte[] textBytes = Encoding.ASCII.GetBytes((string)data); // One data length TDSUtilities.WriteUShort(destination, (ushort)textBytes.Length); // Data destination.Write(textBytes, 0, textBytes.Length); } break; } case TDSDataType.NVarChar: { // Check if data is available if (data == null) { // No data TDSUtilities.WriteUShort(destination, 0xFFFF); } else { // Get bytes byte[] textBytes = Encoding.Unicode.GetBytes((string)data); // One data length TDSUtilities.WriteUShort(destination, (ushort)textBytes.Length); // Data destination.Write(textBytes, 0, textBytes.Length); } break; } case TDSDataType.BigVarBinary: case TDSDataType.BigBinary: { // Check if data is available if (data == null) { // No data TDSUtilities.WriteUShort(destination, 0xFFFF); } else { // Get bytes byte[] bytes = (byte[])data; // One data length TDSUtilities.WriteUShort(destination, (ushort)bytes.Length); // Data destination.Write(bytes, 0, bytes.Length); } break; } default: { // We don't know this type throw new NotImplementedException(string.Format("Unrecognized data type {0} for deflation", column.DataType)); } } }
/// <summary> /// Inflate the token /// </summary> /// <param name="source">Stream to inflate the token from</param> /// <returns>TRUE if inflation is complete</returns> public bool Inflate(Stream source) { // Read user type UserType = TDSUtilities.ReadUInt(source); // Read flags Flags = new TDSColumnDataFlags(TDSUtilities.ReadUShort(source)); // Read server type DataType = (TDSDataType)source.ReadByte(); // Dispatch further reading based on the type switch (DataType) { case TDSDataType.Binary: case TDSDataType.VarBinary: case TDSDataType.Char: case TDSDataType.VarChar: // The above types are deprecated after TDS 7205. case TDSDataType.BitN: case TDSDataType.Guid: case TDSDataType.IntN: case TDSDataType.MoneyN: case TDSDataType.FloatN: case TDSDataType.DateTimeN: { // Byte length DataTypeSpecific = source.ReadByte(); break; } case TDSDataType.DateN: { // No details DataTypeSpecific = null; break; } case TDSDataType.TimeN: case TDSDataType.DateTime2N: case TDSDataType.DateTimeOffsetN: { // Scale DataTypeSpecific = source.ReadByte(); break; } case TDSDataType.DecimalN: case TDSDataType.NumericN: { // Read values byte length = (byte)source.ReadByte(); byte precision = (byte)source.ReadByte(); byte scale = (byte)source.ReadByte(); // Decimal data type specific DataTypeSpecific = new TDSDecimalColumnSpecific(length, precision, scale); break; } case TDSDataType.BigBinary: case TDSDataType.BigVarBinary: { // Short length DataTypeSpecific = TDSUtilities.ReadUShort(source); break; } case TDSDataType.BigChar: case TDSDataType.BigVarChar: case TDSDataType.NChar: case TDSDataType.NVarChar: { // SHILOH CHAR types have collation associated with it. TDSShilohVarCharColumnSpecific typedSpecific = new TDSShilohVarCharColumnSpecific(); // Read length typedSpecific.Length = TDSUtilities.ReadUShort(source); // Create collation typedSpecific.Collation = new TDSColumnDataCollation(); // Read collation typedSpecific.Collation.WCID = TDSUtilities.ReadUInt(source); typedSpecific.Collation.SortID = (byte)source.ReadByte(); DataTypeSpecific = typedSpecific; break; } case TDSDataType.Text: case TDSDataType.NText: { // YukonTextType.Len + YukonTextType.tdsCollationInfo + YukonTextType.cParts // cb = sizeof(LONG) + sizeof(TDSCOLLATION) + sizeof(BYTE); break; } case TDSDataType.Image: { // Data length DataTypeSpecific = TDSUtilities.ReadUInt(source); break; } case TDSDataType.SSVariant: { // Data length DataTypeSpecific = TDSUtilities.ReadUInt(source); break; } case TDSDataType.Udt: { // hr = GetUDTColFmt(pvOwner, dwTimeout); break; } case TDSDataType.Xml: { // cb = sizeof(lpColFmt->YukonXmlType.bSchemaPresent); break; } } // Check if table name is available if (DataType == TDSDataType.Text || DataType == TDSDataType.NText || DataType == TDSDataType.Image) { // Allocate table name container TableName = new List <string>(); // Read part count byte partCount = (byte)source.ReadByte(); // Write each part for (byte bPart = 0; bPart < partCount; bPart++) { // Read table part length and value TableName.Add(TDSUtilities.ReadString(source, (ushort)(TDSUtilities.ReadUShort(source) * 2))); } } // Read column name Name = TDSUtilities.ReadString(source, (ushort)(source.ReadByte() * 2)); return(true); }
/// <summary> /// Inflate the token /// </summary> /// <param name="source">Stream to inflate the token from</param> /// <returns>TRUE if inflation is complete</returns> public override bool Inflate(Stream source) { // Reset inflation size InflationSize = 0; // We skip option identifier because it was read by construction factory // Read the length of the data for the option uint optionDataLength = TDSUtilities.ReadUInt(source); // Update inflation offset InflationSize += sizeof(uint); // Read one byte for the flags byte temp = (byte)source.ReadByte(); // Update inflation offset InflationSize += sizeof(byte); // Get the bit and set as a fedauth echo bit Echo = (TdsPreLoginFedAuthRequiredOption)(temp & 0x01); // Get the remaining 7 bits and set as a library. Library = (TDSFedAuthLibraryType)(temp >> 1); // When using the ADAL library, a FedAuthToken is never included, nor is its length included if (Library != TDSFedAuthLibraryType.MSAL) { // Length of the FedAuthToken uint fedauthTokenLen = TDSUtilities.ReadUInt(source); // Update inflation offset InflationSize += sizeof(uint); // Check if the fedauth token is in the login7 if (fedauthTokenLen > 0) { // Allocate a container Token = new byte[fedauthTokenLen]; // Read the Fedauth token. source.Read(Token, 0, (int)fedauthTokenLen); // Update inflation offset InflationSize += fedauthTokenLen; } } else { // Instead the workflow is included Workflow = (TDSFedAuthMSALWorkflow)source.ReadByte(); } switch (Library) { case TDSFedAuthLibraryType.IDCRL: IsRequestingAuthenticationInfo = false; return(ReadIDCRLLogin(source, optionDataLength)); case TDSFedAuthLibraryType.SECURITY_TOKEN: IsRequestingAuthenticationInfo = false; return(ReadSecurityTokenLogin(source, optionDataLength)); case TDSFedAuthLibraryType.MSAL: IsRequestingAuthenticationInfo = true; return(true); default: return(false); } }
/// <summary> /// Inflate the token /// NOTE: This operation is not continuable and assumes that the entire token is available in the stream /// </summary> /// <param name="source">Stream to inflate the token from</param> /// <returns>TRUE if inflation is complete</returns> public override bool Inflate(Stream source) { // Prepare a list of options IList <TDSPreLoginTokenOption> options = new List <TDSPreLoginTokenOption>(); // Inflate all options until terminator is detected do { // Create a new option options.Add(new TDSPreLoginTokenOption()); // Inflate it if (!options[options.Count - 1].Inflate(source)) { return(false); } }while (options[options.Count - 1].Type != TDSPreLoginTokenOptionType.Terminator); // Order the options in ascending order by offset // For the most cases this should not change the order of the options in the stream, but just in case options = options.OrderBy(o => o.Position).ToList(); // Calculate current inflation offset ushort inflationOffset = (ushort)options.Sum(o => o.TokenLength); // Iterate through each option and inflate it foreach (TDSPreLoginTokenOption option in options) { // Ensure that current offset points to the option while (inflationOffset < option.Position) { // Read the stream source.ReadByte(); // Advance position inflationOffset++; } // Check the type of the pre-login packet option type switch (option.Type) { case TDSPreLoginTokenOptionType.Version: { // Check if version fits if (option.Length >= 6) { // Read the data of the specified length at the specified position Version = new Version( source.ReadByte() & 0xff, // Major source.ReadByte(), // Minor (source.ReadByte() << 8) + source.ReadByte()); // Build (swap bytes) // Read sub-build SubBuild = TDSUtilities.ReadUShort(source); // Update the offset inflationOffset += 6; } break; } case TDSPreLoginTokenOptionType.Encryption: { // Check is option fits if (option.Length >= 1) { // Read encryption Encryption = (TDSPreLoginTokenEncryptionType)source.ReadByte(); // Update the offset inflationOffset += 1; } break; } case TDSPreLoginTokenOptionType.Instance: { // Currently does nothing. break; } case TDSPreLoginTokenOptionType.ThreadID: { // Check if thread ID fits if (option.Length >= 4) { // Read the data of the specified length at the specified position (big-endian) ThreadID = TDSUtilities.ReadUInt(source); // Update the offset inflationOffset += 4; } break; } case TDSPreLoginTokenOptionType.Mars: { // Check is option fits if (option.Length >= 1) { // Read byte IsMARS = (source.ReadByte() == 0x01); // Update the offset inflationOffset += 1; } break; } case TDSPreLoginTokenOptionType.TraceID: { if (option.Length >= 36) { // Allocate memory ClientTraceID = new byte[16]; // Read connection Trace ID source.Read(ClientTraceID, 0, 16); // Allocate memory ActivityID = new byte[20]; // Read Activity ID. source.Read(ActivityID, 0, 20); // Update the offset inflationOffset += 36; } break; } case TDSPreLoginTokenOptionType.FederatedAuthenticationRequired: { if (option.Length >= 1) { // Read authentication type. FedAuthRequired = (TdsPreLoginFedAuthRequiredOption)source.ReadByte(); // Update the offset inflationOffset += 1; } break; } case TDSPreLoginTokenOptionType.NonceOption: { if (option.Length >= 32) { //Allocate memory Nonce = new byte[32]; // Read Nonce. source.Read(Nonce, 0, 32); // Update the offset inflationOffset += 32; } break; } } } return(true); }
/// <summary> /// Deflate the token /// </summary> /// <param name="destination">Stream to deflate token to</param> public override void Deflate(Stream destination) { // Write option identifier destination.WriteByte((byte)FeatureID); // Calculate Feature Data length uint optionDataLength = (uint)(sizeof(byte) // Options size (library and Echo) + ((Token == null && IsRequestingAuthenticationInfo) ? 0 : sizeof(uint)) // Fedauth token length + (Token == null ? 0 : (uint)Token.Length) // Fedauth Token + (Nonce == null ? 0 : s_nonceDataLength) // Nonce + (ChannelBingingToken == null ? 0 : (uint)ChannelBingingToken.Length) // Channel binding + (Signature == null ? 0 : s_signatureDataLength) // Signature + (Library == TDSFedAuthLibraryType.MSAL ? 1 : 0)); // Workflow // Write the cache length into the destination TDSUtilities.WriteUInt(destination, optionDataLength); // Construct a byte from fedauthlibrary and fedauth echo. byte temp = (byte)((((byte)(Library) << 1) | (byte)(Echo))); destination.WriteByte(temp); // Write FederatedAuthenticationRequired token. if (Token == null && !IsRequestingAuthenticationInfo) { // Write the length of the token is 0 TDSUtilities.WriteUInt(destination, 0); } else if (Token != null) { // Write the FederatedAuthenticationRequired token length. TDSUtilities.WriteUInt(destination, (uint)Token.Length); // Write the token. destination.Write(Token, 0, Token.Length); } if (Nonce != null) { // Write the nonce destination.Write(Nonce, 0, Nonce.Length); } // Write the Channel Binding length if (ChannelBingingToken != null) { destination.Write(ChannelBingingToken, 0, ChannelBingingToken.Length); } if (Signature != null) { // Write Signature destination.Write(Signature, 0, (int)s_signatureDataLength); } if (Library == TDSFedAuthLibraryType.MSAL) { // Write Workflow destination.WriteByte((byte)Workflow); } }
/// <summary> /// Deflate the token /// </summary> /// <param name="destination">Stream to deflate token to</param> public override void Deflate(Stream destination) { IList <TDSPreLoginTokenOption> options = new List <TDSPreLoginTokenOption>(); // Prepare the sequence of options to serialize options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.Version, 6)); options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.ThreadID, 4)); options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.Mars, 1)); //Check if the option is needed. if (ActivityID != null && ClientTraceID != null) { options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.TraceID, 36)); } // Add Federated authentication if (FedAuthRequired == TdsPreLoginFedAuthRequiredOption.FedAuthRequired || FedAuthRequired == TdsPreLoginFedAuthRequiredOption.Illegal) { options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.FederatedAuthenticationRequired, 1)); } // Check if the option is needed to be added. if (Nonce != null) { options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.NonceOption, (ushort)Nonce.Length)); } options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.Encryption, 1)); options.Add(new TDSPreLoginTokenOption(TDSPreLoginTokenOptionType.Terminator, 0)); // Calculate the total size of the token metadata ushort dataOffset = (ushort)options.Sum(t => t.TokenLength); // Update all the offsets foreach (TDSPreLoginTokenOption option in options) { // Update token offset option.Position = dataOffset; // Update data offset dataOffset += option.Length; } // Serialize all tokens first foreach (TDSPreLoginTokenOption option in options) { // Deflate a token option option.Deflate(destination); } // Write version destination.WriteByte((byte)(Version.Major & 0xff)); destination.WriteByte((byte)(Version.Minor & 0xff)); destination.WriteByte((byte)((Version.Build >> 8) & 0xff)); destination.WriteByte((byte)(Version.Build & 0xff)); // Write sub-version TDSUtilities.WriteUShort(destination, SubBuild); // Write thread ID TDSUtilities.WriteUInt(destination, ThreadID); // Write MARS destination.WriteByte((byte)(IsMARS ? 0x01 : 0x00)); // Write traceID if (ClientTraceID != null) { destination.Write(ClientTraceID, 0, ClientTraceID.Length); } // Write ActivityID if (ActivityID != null) { destination.Write(ActivityID, 0, ActivityID.Length); } // Write federated auth required part if (FedAuthRequired == TdsPreLoginFedAuthRequiredOption.FedAuthRequired || FedAuthRequired == TdsPreLoginFedAuthRequiredOption.Illegal) { destination.WriteByte((byte)FedAuthRequired); } // Write Nonce. if (Nonce != null) { destination.Write(Nonce, 0, Nonce.Length); } // Write Encryption destination.WriteByte((byte)Encryption); }
public override TDSMessageCollection ExecuteRPC(ITDSServerSession session, TDSMessage message) { TDSRPCRequestToken rpc = message[0] as TDSRPCRequestToken; TDSDoneToken done = new TDSDoneToken(TDSDoneTokenStatusType.Final, TDSDoneTokenCommandType.Done, 0); if (String.IsNullOrEmpty(rpc.ProcName)) { if (rpc.ProcID == TDSRPCRequestTokenProcID.Sp_ExecuteSql) { var sqlQuery = rpc.Parameters.First(); if (sqlQuery.DataType == TDSDataType.NVarChar) { var sql = sqlQuery.Value.ToString(); var result = TryGet(sql, rpc.Parameters); if (null != result) { if (result.GetRecords().Any()) { var tokens = ReturnTable(result); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, (ulong)result.GetRecords().Count()); tokens.Add(doneToken); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, tokens.ToArray()))); } else if (result.ReturnValue.HasValue) { var retVal = new TDSReturnValueToken(); retVal.Flags.Updatable = TDSColumnDataUpdatableFlag.ReadOnly; retVal.DataType = TDSDataType.IntN; retVal.DataTypeSpecific = (byte)4; retVal.Flags.IsComputed = true; retVal.Flags.IsNullable = true; // TODO: Must be nullable, otherwise something is wrong with SqlClient retVal.ParamName = "@RETURN_VALUE"; retVal.Value = (int)result.ReturnValue.Value; retVal.Status = TDSReturnValueStatus.Output; TDSDoneInProcToken doneInRpc = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, 1); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, retVal, doneInRpc))); } else { TDSDoneInProcToken doneInRpc = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, result.Scalar); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, doneInRpc))); } } else { PrintMissignQuery(sql, rpc.Parameters); } } } } else { var text = rpc.ProcName.ToLowerInvariant(); var result = TryGet(text, rpc.Parameters); if (null != result) { if (result.GetRecords().Any()) { var tokens = ReturnTable(result); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.Select, (ulong)result.GetRecords().Count()); tokens.Add(doneToken); // Log response TDSUtilities.Log(Log, "Response", doneToken); // Serialize tokens into the message return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, tokens.ToArray()))); } else { TDSDoneInProcToken doneIn = new TDSDoneInProcToken(TDSDoneTokenStatusType.Count, TDSDoneTokenCommandType.DoneInProc, result.Scalar); return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, doneIn))); } } else { PrintMissignQuery(text, rpc.Parameters); } } return(new TDSMessageCollection(new TDSMessage(TDSMessageType.Response, done))); }
/// <summary> /// Inflate the token /// </summary> /// <param name="source">Stream to inflate the token from</param> public override bool Inflate(Stream source) { // We skip the token identifier because it is read by token factory // Current inflation offset uint inflationOffset = 0; // Read the length of the token uint tokenLength = TDSUtilities.ReadUInt(source); // NOTE: Length is excluded from the token length // Check if we still have space left to read if (inflationOffset >= tokenLength) { // We read the whole token return(true); } // Read sequence number SequenceNumber = (int)TDSUtilities.ReadUInt(source); // Update inflation offset inflationOffset += sizeof(uint); // Check if we still have space left to read if (inflationOffset >= tokenLength) { // We read the whole token return(true); } // Read status byte status = (byte)source.ReadByte(); // Update inflation offset inflationOffset += sizeof(byte); // Check if we still have space left to read if (inflationOffset >= tokenLength) { // We read the whole token return(true); } // Parse status IsRecoverable = ((status & 0x01) != 0); // Read while we have data while (tokenLength > inflationOffset) { // Read a byte that identifies the session state slot byte stateID = (byte)source.ReadByte(); // Update current position inflationOffset += sizeof(byte); // Option being inflated TDSSessionStateOption option = null; // Dispatch inflation based on the state switch (stateID) { // UserOptionAll case TDSSessionStateUserOptionsOption.ID: { // Create a new option option = new TDSSessionStateUserOptionsOption(); break; } // DateFirstDateFormat case TDSSessionStateDateFirstDateFormatOption.ID: { // Create a new option option = new TDSSessionStateDateFirstDateFormatOption(); break; } // DbDeadlockPri case TDSSessionStateDeadlockPriorityOption.ID: { // Create a new option option = new TDSSessionStateDeadlockPriorityOption(); break; } // LockTimeout case TDSSessionStateLockTimeoutOption.ID: { // Create a new option option = new TDSSessionStateLockTimeoutOption(); break; } // IsoFips case TDSSessionStateISOFipsOption.ID: { // Create a new option option = new TDSSessionStateISOFipsOption(); break; } // TextSize case TDSSessionStateTextSizeOption.ID: { // Create a new option option = new TDSSessionStateTextSizeOption(); break; } // ContextInfo case TDSSessionStateContextInfoOption.ID: { // Create a new option option = new TDSSessionStateContextInfoOption(); break; } default: { // Create a new option option = new TDSSessionStateGenericOption(stateID); break; } } // Inflate the option option.Inflate(source); // Register option with the collection Options.Add(option); // Update current length with the inflation size of the data inflationOffset += option.InflationSize; } return(true); }
/// <summary> /// Advances one step in SSPI authentication sequence /// </summary> protected virtual TDSMessageCollection ContinueSSPIAuthentication(ITDSServerSession session, byte[] payload) { // Response to send to the client SSPIResponse response; try { // Check if we have an SSPI context if (session.NTUserAuthenticationContext == null) { // This is the first step so we need to create a server context and initialize it session.NTUserAuthenticationContext = SSPIContext.CreateServer(); // Run the first step of authentication response = session.NTUserAuthenticationContext.StartServerAuthentication(payload); } else { // Process SSPI request from the client response = session.NTUserAuthenticationContext.ContinueServerAuthentication(payload); } } catch (Exception e) { // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(12345, 1, 15, "Failed to accept security SSPI context", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseErrorMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(12345, 1, 15, e.Message, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseErrorMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseErrorMessage.Add(doneToken); // Respond with a single message return(new TDSMessageCollection(responseErrorMessage)); } // Message collection to respond with TDSMessageCollection responseMessages = new TDSMessageCollection(); // Check if there's a response if (response != null) { // Check if there's a payload if (response.Payload != null) { // Create SSPI token TDSSSPIToken sspiToken = new TDSSSPIToken(response.Payload); // Log response TDSUtilities.Log(Arguments.Log, "Response", sspiToken); // Prepare response message with a single response token responseMessages.Add(new TDSMessage(TDSMessageType.Response, sspiToken)); // Check if we can complete login if (!response.IsFinal) { // Send the message to the client return(responseMessages); } } } // Reset SQL user identifier since we're using NT authentication session.SQLUserID = null; // Append successfully authentication response responseMessages.AddRange(OnAuthenticationCompleted(session)); // Return the message with SSPI token return(responseMessages); }
/// <summary> /// Handler for login request /// </summary> public override TDSMessageCollection OnLogin7Request(ITDSServerSession session, TDSMessage request) { // Inflate login7 request from the message TDSLogin7Token loginRequest = request[0] as TDSLogin7Token; // Check if arguments are of the authenticating TDS server if (Arguments is AuthenticatingTDSServerArguments) { // Cast to authenticating TDS server arguments AuthenticatingTDSServerArguments ServerArguments = Arguments as AuthenticatingTDSServerArguments; // Check if we're still processing normal login if (ServerArguments.ApplicationIntentFilter != ApplicationIntentFilterType.All) { // Check filter if ((ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.ReadOnly && loginRequest.TypeFlags.ReadOnlyIntent != TDSLogin7TypeFlagsReadOnlyIntent.ReadOnly) || (ServerArguments.ApplicationIntentFilter == ApplicationIntentFilterType.None)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application intent: " + loginRequest.TypeFlags.ReadOnlyIntent.ToString(), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application intent filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return(new TDSMessageCollection(responseMessage)); } } // Check if we're still processing normal login and there's a filter to check if (ServerArguments.ServerNameFilterType != ServerNameFilterType.None) { // Check each algorithm if ((ServerArguments.ServerNameFilterType == ServerNameFilterType.Equals && string.Compare(ServerArguments.ServerNameFilter, loginRequest.ServerName, true) != 0) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.StartsWith && !loginRequest.ServerName.StartsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.EndsWith && !loginRequest.ServerName.EndsWith(ServerArguments.ServerNameFilter)) || (ServerArguments.ServerNameFilterType == ServerNameFilterType.Contains && !loginRequest.ServerName.Contains(ServerArguments.ServerNameFilter))) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, string.Format("Received server name \"{0}\", expected \"{1}\" using \"{2}\" algorithm", loginRequest.ServerName, ServerArguments.ServerNameFilter, ServerArguments.ServerNameFilterType), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by server name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return(new TDSMessageCollection(responseMessage)); } } // Check if packet size filter is applied if (ServerArguments.PacketSizeFilter != null) { // Check if requested packet size is the same as the filter specified if (loginRequest.PacketSize != ServerArguments.PacketSizeFilter.Value) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the reason TDSErrorToken errorToken = new TDSErrorToken(1919, 1, 14, string.Format("Received packet size \"{0}\", expected \"{1}\"", loginRequest.PacketSize, ServerArguments.PacketSizeFilter.Value), Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token with the final errorToken errorToken = new TDSErrorToken(1919, 1, 14, "Connection is denied by packet size filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the errorToken token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Return only a single message with the collection return(new TDSMessageCollection(responseMessage)); } } // If we have an application name filter if (ServerArguments.ApplicationNameFilter != null) { // If we are supposed to block this connection attempt if (loginRequest.ApplicationName.Equals(ServerArguments.ApplicationNameFilter, System.StringComparison.OrdinalIgnoreCase)) { // Log request to which we're about to send a failure TDSUtilities.Log(Arguments.Log, "Request", loginRequest); // Prepare ERROR token with the denial details TDSErrorToken errorToken = new TDSErrorToken(18456, 1, 14, "Received application name: " + loginRequest.ApplicationName, Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet TDSMessage responseMessage = new TDSMessage(TDSMessageType.Response, errorToken); // Prepare ERROR token for the final decision errorToken = new TDSErrorToken(18456, 1, 14, "Connection is denied by application name filter", Arguments.ServerName); // Log response TDSUtilities.Log(Arguments.Log, "Response", errorToken); // Serialize the error token into the response packet responseMessage.Add(errorToken); // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final | TDSDoneTokenStatusType.Error); // Log response TDSUtilities.Log(Arguments.Log, "Response", doneToken); // Serialize DONE token into the response packet responseMessage.Add(doneToken); // Put a single message into the collection and return it return(new TDSMessageCollection(responseMessage)); } } } // Return login response from the base class return(base.OnLogin7Request(session, request)); }