Example #1
0
        /// <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);
        }
Example #2
0
        /// <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);
        }
Example #5
0
        /// <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));
                }
            }
        }
Example #6
0
        /// <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);
        }
Example #7
0
        /// <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);
        }
Example #9
0
        /// <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);
        }
Example #10
0
        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));
            }
            }
        }
Example #13
0
        /// <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);
            }
        }
Example #15
0
        /// <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);
            }
        }
Example #17
0
        /// <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);
        }
Example #18
0
        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)));
        }
Example #19
0
        /// <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);
        }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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));
        }