示例#1
0
        private static void WriteTransactionHeader(TdsPackageWriter writer, TdsEnums.TransactionManagerRequestType request, long sqlTransactionId)
        {
            writer.NewPackage(TdsEnums.MT_TRANS);
            writer.WriteMarsHeader(sqlTransactionId);

            writer.WriteInt16((short)request); // write TransactionManager Request type
        }
示例#2
0
 public static void WriteParameterLen(this TdsPackageWriter writer, TdsMetaType.MetaDataWrite metaType, int size, bool isNull)
 {
     if (isNull)
     {
         return;
     }
     //write length of the parameter
     if (metaType.IsPlp)
     {
         writer.WriteInt64(size);
     }
     else if (metaType.IsLong)
     {
         // text/image/SQLVariant have a 4 byte length, plp datatypes have 8 byte lengths
         writer.WriteInt32(size);
     }
     else if (metaType.NullableType == TdsEnums.SQLDATETIME2 || metaType.NullableType == TdsEnums.SQLTIME || metaType.NullableType == TdsEnums.SQLDATETIMEOFFSET)
     {
         writer.WriteByte((byte)size);
     }
     else if (metaType.NullableType == TdsEnums.SQLBIGVARBINARY || metaType.NullableType == TdsEnums.SQLBIGCHAR || metaType.NullableType == TdsEnums.SQLNCHAR || metaType.NullableType == TdsEnums.SQLNVARCHAR) //skip varchar
     {
         writer.WriteInt16(size);
     }
     else
     {
         writer.WriteByte((byte)size); // 1 byte for everything else
     }
 }
示例#3
0
 public static void SendTransactionCommit(this TdsPackageWriter writer, long sqlTransactionId)
 {
     WriteTransactionHeader(writer, TdsEnums.TransactionManagerRequestType.Commit, sqlTransactionId);
     writer.WriteByte(0); // No xact name
     writer.WriteByte(0); // No flags
     writer.SendLastMessage();
 }
示例#4
0
        public static void SendRpc(this TdsPackageWriter writer, SqlCollations defaultCollation, FormattableString sql, long sqlConnectionId)
        {
            writer.NewPackage(TdsEnums.MT_RPC);
            writer.WriteMarsHeader(sqlConnectionId);

            writer.WriteInt16(0xffff);
            writer.WriteInt16(TdsEnums.RPC_PROCID_EXECUTESQL);

            // Options
            writer.WriteInt16(TdsEnums.RPC_PARAM_DEFAULT);

            // Stream out parameters
            var parameters = CreateParameters(sql);

            foreach (var parameter in parameters)
            {
                // parameters can be unnamed
                var param  = parameter;
                var value  = parameter.Value;
                var isNull = value == null;

                writer.WriteByteLenString(param.Name);

                // Write parameter status
                writer.WriteByte(parameter.Status);
                var p  = parameter;
                var mt = p.MetaData;
                WriteTdsTypeInfo(writer, mt, p.Size, p.IsNull, defaultCollation, p.Scale);
                WriteValue(writer, value, mt, isNull);
            }

            writer.SendLastMessage();
        }
示例#5
0
        private void SetupColMetaData(TdsPackageReader reader, TdsPackageWriter writer, int tdsType, byte precision, byte scale, bool isPlp)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            var r         = reader.CurrentResultSet.ColumnsMetadata = new ColumnsMetadata(1);
            var w         = writer.ColumnsMetadata = new MetadataBulkCopy[1];
            var collation = new SqlCollations {
                Info = 0x00d00409, SortId = 0x34
            };
            var encoding = Encoding.GetEncoding(collation.GetCodePage());

            w[0]         = new MetadataBulkCopy();
            r[0].TdsType = (byte)tdsType;
            w[0].TdsType = (byte)tdsType;
            r[0].Scale   = scale;
            w[0].Scale   = scale;
            r[0].IsPlp   = isPlp;
            w[0].IsPlp   = isPlp;
            r[0].IsPlp   = isPlp;
            w[0].Length  = scale;// nullable date testfix

            r[0].Encoding  = encoding;
            w[0].Encoding  = encoding;
            w[0].Collation = collation;

            w[0].Precision = precision;

            w[0].MetaType = TdsMetaType.TdsTypes[tdsType];
            r[0].MetaType = TdsMetaType.TdsTypes[tdsType];

            r[0].IsTextOrImage = r[0].MetaType.IsTextOrImage;
            w[0].IsTextOrImage = r[0].MetaType.IsTextOrImage;
        }
示例#6
0
        private static void WriteSessionRecoveryFeatureRequest(TdsPackageWriter writer, SessionData reconnectData)
        {
            var(_, initialLength, currentLength, writeState) = SessionRecoveryFeatureRequestLengths(reconnectData);
            writer.WriteByte(TdsEnums.FEATUREEXT_SRECOVERY);
            if (reconnectData == null)
            {
                writer.WriteInt32(0);
            }
            else
            {
                writer.WriteInt32(8 + initialLength + currentLength); // length of data w/o total length (initial + current + 2 * sizeof(DWORD))
                writer.WriteInt32(initialLength);
                writer.WriteByteLenString(reconnectData.InitialDatabase);
                writer.WriteCollation(reconnectData.InitialCollation);
                writer.WriteByteLenString(reconnectData.InitialLanguage);
                for (var i = 0; i < SessionData.MaxNumberOfSessionStates; i++)
                {
                    if (reconnectData.InitialState[i] != null)
                    {
                        writer.WriteByte((byte)i);
                        if (reconnectData.InitialState[i].Length < 0xFF)
                        {
                            writer.WriteByte((byte)reconnectData.InitialState[i].Length);
                        }
                        else
                        {
                            writer.WriteByte(0xFF);
                            writer.WriteInt32(reconnectData.InitialState[i].Length);
                        }

                        writer.WriteByteArray(reconnectData.InitialState[i]);
                    }
                }

                writer.WriteInt32(currentLength);
                writer.WriteByteLenString(reconnectData.Database != reconnectData.InitialDatabase ? reconnectData.Database : null);
                writer.WriteCollation(SqlCollations.AreSame(reconnectData.InitialCollation, reconnectData.Collation) ? null : reconnectData.Collation);
                writer.WriteByteLenString(reconnectData.Language != reconnectData.InitialLanguage ? reconnectData.Language : null);
                for (var i = 0; i < SessionData.MaxNumberOfSessionStates; i++)
                {
                    if (writeState[i])
                    {
                        writer.WriteByte((byte)i);
                        if (reconnectData.Delta[i].DataLength < 0xFF)
                        {
                            writer.WriteByte((byte)reconnectData.Delta[i].DataLength);
                        }
                        else
                        {
                            writer.WriteByte(0xFF);
                            writer.WriteInt32(reconnectData.Delta[i].DataLength);
                        }

                        writer.WriteByteArray(reconnectData.Delta[i].Data);
                    }
                }
            }
        }
示例#7
0
        public static void SendExecuteBatch(this TdsPackageWriter tdsPackageWriter, string text, long sqlConnectionId)
        {
            tdsPackageWriter.NewPackage(TdsEnums.MT_SQL);

            tdsPackageWriter.WriteMarsHeader(sqlConnectionId);

            tdsPackageWriter.WriteUnicodeString(text);
            tdsPackageWriter.SendLastMessage();
        }
示例#8
0
        public static void SendTransactionBegin(this TdsPackageWriter writer, TdsEnums.TransactionManagerIsolationLevel isoLevel)
        {
            var transactionName = "";

            WriteTransactionHeader(writer, TdsEnums.TransactionManagerRequestType.Begin, 0);
            writer.WriteByte((byte)isoLevel);
            writer.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string).
            writer.WriteUnicodeString(transactionName);
            writer.SendLastMessage();
        }
示例#9
0
        public static void SendTransactionRollback(this TdsPackageWriter writer, long sqlTransactionId)
        {
            var transactionName = "";

            WriteTransactionHeader(writer, TdsEnums.TransactionManagerRequestType.Rollback, sqlTransactionId);

            writer.WriteByte((byte)(transactionName.Length * 2)); // Write number of bytes (unicode string).
            writer.WriteUnicodeString(transactionName);
            writer.WriteByte(0);                                  // No flags
            writer.SendLastMessage();
        }
示例#10
0
 public static void WriteTypeInfoLen(this TdsPackageWriter writer, TdsMetaType.MetaDataWrite metaType, int size, bool isNull)
 {
     //write length or isNull information about the type
     if (metaType.IsPlp)
     {
         if (isNull)
         {
             writer.WriteInt64(unchecked ((long)TdsEnums.SQL_PLP_NULL));
         }
         else
         {
             writer.WriteInt64(size);
         }
     }
     else if (metaType.IsLong)
     {
         // text/image/SQLVariant have a 4 byte length, plp datatypes have 8 byte lengths
         if (isNull)
         {
             writer.WriteInt32(unchecked ((int)TdsEnums.VARLONGNULL));
         }
         else
         {
             writer.WriteInt32(size);
         }
     }
     else if (metaType.NullableType == TdsEnums.SQLDATETIME2 || metaType.NullableType == TdsEnums.SQLTIME || metaType.NullableType == TdsEnums.SQLDATETIMEOFFSET)
     {
         if (isNull)
         {
             writer.WriteByte(TdsEnums.FIXEDNULL);
         }
         else
         {
             writer.WriteByte((byte)size);
         }
     }
     else if (metaType.NullableType == TdsEnums.SQLBIGVARBINARY || metaType.NullableType == TdsEnums.SQLBIGCHAR || metaType.NullableType == TdsEnums.SQLNCHAR || metaType.NullableType == TdsEnums.SQLNVARCHAR) //skip varchar
     {
         // non-long but variable length column, must be a BIG* type: 2 byte length
         writer.WriteInt16(isNull ? TdsEnums.VARNULL : size);
     }
     else
     {
         if (isNull)
         {
             writer.WriteByte(TdsEnums.FIXEDNULL);
         }
         else
         {
             writer.WriteByte((byte)size); // 1 byte for everything else
         }
     }
 }
示例#11
0
 public static void WriteByteLenString(this TdsPackageWriter writer, string?s)
 {
     if (string.IsNullOrEmpty(s))
     {
         writer.WriteByte(0);
     }
     else
     {
         writer.WriteByte(checked ((byte)s.Length));
         writer.WriteUnicodeString(s);
     }
 }
示例#12
0
 public static void WriteCollation(this TdsPackageWriter writer, SqlCollations?collation)
 {
     if (collation == null)
     {
         writer.WriteByte(0);
     }
     else
     {
         writer.WriteByte(sizeof(uint) + sizeof(byte));
         writer.WriteUInt32(collation.Info);
         writer.WriteByte(collation.SortId);
     }
 }
示例#13
0
        public static void WriteValue(TdsPackageWriter writer, object?value, TdsMetaType.MetaDataWrite metaData, bool isNull)
        {
            // write the value now
            if (isNull)
            {
                return;
            }
            switch (value)
            {
            case string v:
                writer.WriteUnicodeString(v);
                break;

            case decimal v:
                writer.WriteSqlDecimal(v, 17);
                break;

            case bool v:
                writer.WriteByte(v ? 1 : 0);
                break;

            case DateTime v:
                writer.WriteDateTime(v);
                break;

            case byte v:
                writer.WriteByte(v);
                break;

            case short v:
                writer.WriteInt16(v);
                break;

            case int v:
                writer.WriteInt32(v);
                break;

            case long v:
                writer.WriteInt64(v);
                break;

            case float v:
                writer.WriteFloat(v);
                break;

            case double v:
                writer.WriteDouble(v);
                break;
            }
        }
示例#14
0
        public void get_npSniHandle()
        {
            const bool marsOn = false;
            var        p      = new ServerConnectionOptions(@"(localdb)\mssqllocaldb", false);
            var        handle = new TdsStreamNamedPipes(p.PipeServerName, p.PipeName, 15);
            var        writer = new TdsPackageWriter(handle);
            var        reader = new TdsPackageReader(handle);

            writer.SendPreLoginHandshake("", marsOn);
            reader.CheckBuffer(8);
            var result = ParserPreLogin.ParsePreLoginHandshake(reader.ReadBuffer, TdsEnums.HEADER_LEN, EncryptionOptions.OFF);

            Assert.Equal(EncryptionOptions.OFF, result);
        }
示例#15
0
        public static void WriteMarsHeader(this TdsPackageWriter writer, long sqlTransactionId)
        {
            const int marsHeaderSize    = 18; // 4 + (2 + 8 + 4)= size + data
            const int totalHeaderLength = 22; // 4 + (4 + 2 + 8 + 4) size+mars

            writer.WriteInt32(totalHeaderLength);

            writer.WriteInt32(marsHeaderSize);

            writer.WriteInt16(TdsEnums.HEADERTYPE_MARS);

            writer.WriteInt64(sqlTransactionId);

            writer.WriteInt32(1);
        }
示例#16
0
        public static void WriteBulkInsertColMetaData(TdsPackageWriter writer)
        {
            //0x81,0x01,0x00,//colmetadata 0x001 column
            //0x00,0x00,0x00,0x00,//usertype ignore
            //0x09,0x00, //flags
            //0x26,0x04, //int 4
            //0x02,0x49,0x00,0x64,0x00, //columnname 2 chars ID
            var columns = writer.ColumnsMetadata;

            writer.WriteByte(TdsEnums.SQLCOLMETADATA);
            writer.WriteInt16(columns.Length);
            foreach (var column in columns)
            {
                WriteColumn(writer, column);
            }
        }
示例#17
0
        private static void WriteOptions(TdsPackageWriter writer, string instanceName, bool marsOn)
        {
            for (var option = (int)PreLoginOptions.VERSION; option < (int)PreLoginOptions.NUMOPT; option++)
            {
                switch (option)
                {
                case (int)PreLoginOptions.VERSION:
                    // Major and minor
                    writer.WriteByte(0);
                    writer.WriteByte(0);
                    // Build (Big Endian)
                    writer.WriteByte(0);
                    writer.WriteByte(0);
                    // Sub-build (Little Endian)
                    writer.WriteByte(0);
                    writer.WriteByte(0);
                    break;

                case (int)PreLoginOptions.ENCRYPT:
                    writer.WriteByte((byte)EncryptionOptions.NOT_SUP);
                    break;

                case (int)PreLoginOptions.INSTANCE:
                    foreach (var c in instanceName)
                    {
                        writer.WriteByte(c);
                    }
                    writer.WriteByte(0);     // null terminate
                    break;

                case (int)PreLoginOptions.THREADID:
                    writer.WriteUInt32(0);
                    break;

                case (int)PreLoginOptions.MARS:
                    writer.WriteByte((byte)(marsOn ? 1 : 0));     // null terminate
                    break;

                case (int)PreLoginOptions.TRACEID:
                    writer.WriteByteArray(new byte[GuidSize]);
                    writer.WriteByteArray(new byte[GuidSize]);
                    writer.WriteUInt32(0);
                    break;
                }
            }
        }
示例#18
0
        public static void SendPreLoginHandshake(this TdsPackageWriter writer, string instanceName, bool marsOn)
        {
            // PreLoginHandshake buffer consists of:
            // 1) Standard header, with type = MT_PRELOGIN
            // 2) Consecutive 5 bytes for each option, (1 byte length, 2 byte offset, 2 byte buffer length)
            // 3) Consecutive data blocks for each option

            // NOTE: packet data needs to be big endian - not the standard little endian used by
            // the rest of the parser.

            writer.NewPackage(TdsEnums.MT_PRELOGIN);
            WriteHeader(writer, instanceName);
            WriteOptions(writer, instanceName, marsOn);

            // Write out last option - to let server know the second part of packet completed
            writer.SendLastMessage();
        }
示例#19
0
        private static void WriteColumn(TdsPackageWriter writer, MetadataBulkCopy md)
        {
            writer.WriteInt32(0x0);

            writer.WriteByte(md.Flag1);
            writer.WriteByte(md.Flag2);
            writer.WriteByte(md.TdsType);
            var mt = TdsMetaType.TdsTypes[md.TdsType];

            if (mt.LenBytes == 1)
            {
                writer.WriteByte(md.Length);
            }
            if (mt.LenBytes == 2)
            {
                writer.WriteInt16(md.Length);
            }
            if (mt.LenBytes == 4)
            {
                writer.WriteInt32(md.Length);
            }

            if (mt.HasPrecision)
            {
                writer.WriteByte(md.Precision);
            }
            if (mt.HasScale)
            {
                writer.WriteByte(md.Scale);
            }
            if (mt.HasCollation)
            {
                writer.WriteUInt32(md.Collation.Info);
                writer.WriteByte(md.Collation.SortId);
            }

            if (mt.IsTextOrImage)
            {
                writer.WriteInt16(md.PartTableName.TableName.Length);
                writer.WriteUnicodeString(md.PartTableName.TableName);
            }

            writer.WriteByte((byte)md.Column.Length);
            writer.WriteUnicodeString(md.Column);
        }
示例#20
0
        public static void WriteTdsTypeInfo(this TdsPackageWriter writer, TdsMetaType.MetaDataWrite metaData, int size, bool isNull, SqlCollations defaultCollation, byte scale)
        {
            var mt = metaData;

            writer.WriteByte(mt.NullableType);

            writer.WriteTypeInfoLen(mt, size, isNull); //typeinfo varlen
            if (mt.HasCollation)
            {
                writer.WriteCollation2(defaultCollation);
            }
            if (mt.HasPrecision)
            {
                writer.WriteByte(28); //Max clr precision
            }
            if (mt.HasScale)
            {
                writer.WriteByte(scale);                      //
            }
            writer.WriteParameterLen(metaData, size, isNull); //len parameter
        }
示例#21
0
        private static void WriteHeader(TdsPackageWriter writer, string instanceName)
        {
            // Initialize option offset into buffer buffer
            // 5 bytes for each option (1 byte length, 2 byte offset, 2 byte buffer length)
            var offset = (int)PreLoginOptions.NUMOPT * 5 + 1;

            for (var option = (int)PreLoginOptions.VERSION; option < (int)PreLoginOptions.NUMOPT; option++)
            {
                // Fill in the option
                writer.WriteByte((byte)option);

                // Fill in the offset of the option data
                writer.WriteByte((byte)((offset & 0xff00) >> 8)); // send upper order byte
                writer.WriteByte((byte)(offset & 0x00ff));        // send lower order byte

                var optionDataSize = GetOptionSize(option, instanceName);

                writer.WriteByte((byte)((optionDataSize & 0xff00) >> 8));
                writer.WriteByte((byte)(optionDataSize & 0x00ff));
                offset += optionDataSize;
            }

            writer.WriteByte((byte)PreLoginOptions.LASTOPT);
        }
示例#22
0
 public static async Task SendRpcASync(this TdsPackageWriter writer, SqlCollations defaultCollation, FormattableString sql, long sqlConnectionId)
 {
     await Task.Run(() => SendRpc(writer, defaultCollation, sql, sqlConnectionId));
 }
示例#23
0
 public static void WriteTdsTypeInfo(this TdsPackageWriter writer, TdsMetaType.MetaDataWrite metaData, int size, bool isNull)
 {
     WriteTdsTypeInfo(writer, metaData, size, isNull, null, 0);
 }
示例#24
0
 public static void SendSspi(this TdsPackageWriter writer, byte[] sspiData)
 {
     writer.NewPackage(TdsEnums.MT_SSPI);
     writer.WriteByteArray(sspiData);
     writer.SendLastMessage();
 }
示例#25
0
        private void TestIntN(object value, int tdsType, bool nulltest, byte precision = 0, byte scale = 0, bool isPlp = false)
        {
            var stream = new TestStream();
            var writer = new TdsPackageWriter(stream);
            var reader = new TdsPackageReader(stream);

            SetupColMetaData(reader, writer, tdsType, precision, scale, isPlp);
            var columwriter  = new TdsColumnWriter(writer);
            var columnReader = new TdsColumnReader(reader);

            object result;

            if (nulltest)
            {
                writer.NewPackage(TdsEnums.MT_RPC);
                ObjectWriter(columwriter, tdsType, value, nulltest);
                writer.SendLastMessage();
                result = ObjectReader(columnReader, value);
                Assert.Null(result);
            }

            writer.NewPackage(TdsEnums.MT_RPC);
            ObjectWriter(columwriter, tdsType, value, false);
            writer.SendLastMessage();
            result = ObjectReader(columnReader, value);
            switch (value)
            {
            case Money v:
                Assert.Equal((decimal)v, result);
                break;

            case Money4 v:
                Assert.Equal((decimal)v, result);
                break;

            case SqlDate v:
                Assert.Equal((DateTime)v, result);
                break;

            case SqlDateTime2 v:
                Assert.Equal((DateTime)v, result);
                break;

            case SqlDateTime4 v:
                Assert.Equal((DateTime)v, result);
                break;

            case SqlImage v:
                Assert.Equal((byte[])v, result);
                break;

            case SqlUnicode v:
                Assert.Equal((string)v, result);
                break;

            case SqlXml v:
                Assert.Equal((string)v, result);
                break;

            case SqlVariant v:
                switch (v.Value)
                {
                case bool b: Assert.Equal(b, result); break;

                case byte b: Assert.Equal(b, result); break;

                case short b: Assert.Equal(b, result); break;

                case int b: Assert.Equal(b, result); break;

                case long b: Assert.Equal(b, result); break;

                case float b: Assert.Equal(b, result); break;

                case double b: Assert.Equal(b, result); break;

                case DateTime b: Assert.Equal(b, result); break;

                case Guid b: Assert.Equal(b, result); break;

                case decimal b: Assert.Equal(b, result); break;

                case byte[] b: Assert.Equal(b, result); break;

                case string b: Assert.Equal(b, result); break;

                case TimeSpan b: Assert.Equal(b, result); break;

                case DateTimeOffset b: Assert.Equal(b, result); break;

                default:
                    Assert.False(true);
                    break;
                }

                break;

            default:
                Assert.Equal(value, result);
                break;
            }

            Assert.Equal(reader.GetReadEndPos(), reader.GetReadPos());
            if (!new[]
            {
                TdsEnums.SQLBIGBINARY,
                TdsEnums.SQLBIGVARBINARY,
                TdsEnums.SQLBIGVARCHAR,
                TdsEnums.SQLBIGCHAR,
                TdsEnums.SQLTEXT,
                TdsEnums.SQLNVARCHAR,
                TdsEnums.SQLNTEXT,
                TdsEnums.SQLNCHAR,
                TdsEnums.SQLXMLTYPE,
                TdsEnums.SQLIMAGE,
            }.Contains(tdsType) && !(value is SqlVariant v1 && (v1.Value is string s || v1.Value is byte[])))
            {
                Assert.InRange(reader.GetReadPos() - 8, 0, TdsEnums.MaxSizeSqlValue);
            }
        }
示例#26
0
 public TdsColumnWriter(TdsPackageWriter writer)
 {
     _writer  = writer;
     MetaData = writer.ColumnsMetadata;
 }
示例#27
0
 public TdsPackage(ITdsStream tdsStream)
 {
     Reader = new TdsPackageReader(tdsStream);
     Writer = new TdsPackageWriter(tdsStream);
 }
示例#28
0
 public static async Task SendExecuteBatchAsync(this TdsPackageWriter tdsPackageWriter, string text, long sqlConnectionId)
 {
     await Task.Run(() => SendExecuteBatch(tdsPackageWriter, text, sqlConnectionId));
 }
示例#29
0
        public static void SendTdsLogin(this TdsPackageWriter writer, LoginOptions rec, SessionData recoverySessionData)
        {
            const string clientInterfaceName = TdsEnums.SQL_PROVIDER_NAME;

            var requestedFeatures = rec.RequestedFeatures;

            if (recoverySessionData != null && (requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) == 0)
            {
                throw new Exception("Recovery session data without session recovery feature request");
            }
            if (rec.HostName.Length > TdsEnums.MAXLEN_HOSTNAME)
            {
                throw new Exception("_workstationId.Length exceeds the max length for this value");
            }
            if (!rec.UseSspi && rec.UserName.Length > TdsEnums.MAXLEN_USERNAME)
            {
                throw new Exception("_userID.Length exceeds the max length for this value");
            }
            if (!rec.UseSspi && rec.Password.Length > TdsEnums.MAXLEN_PASSWORD)
            {
                throw new Exception("_password.Length exceeds the max length for this value");
            }
            if (rec.ApplicationName.Length > TdsEnums.MAXLEN_APPNAME)
            {
                throw new Exception("_applicationName.Length exceeds the max length for this value");
            }
            if (rec.ServerName.Length > TdsEnums.MAXLEN_SERVERNAME)
            {
                throw new Exception("_dataSource.Length exceeds the max length for this value");
            }
            if (rec.Language.Length > TdsEnums.MAXLEN_LANGUAGE)
            {
                throw new Exception("_currentLanguage .Length exceeds the max length for this value");
            }
            if (rec.Database.Length > TdsEnums.MAXLEN_DATABASE)
            {
                throw new Exception("_initialCatalog.Length exceeds the max length for this value");
            }
            if (rec.AttachDbFilename.Length > TdsEnums.MAXLEN_ATTACHDBFILE)
            {
                throw new Exception("_attachDBFileName.Length exceeds the max length for this value");
            }

            if (clientInterfaceName.Length > TdsEnums.MAXLEN_CLIENTINTERFACE)
            {
                throw new Exception("cchCltIntName can specify at most 128 unicode characters. See Tds spec");
            }


            // get the password up front to use in sspi logic below
            var useFeatureExt = requestedFeatures != TdsEnums.FeatureExtension.None;


            // set the message type

            // length in bytes
            var length = TdsEnums.YUKON_LOG_REC_FIXED_LEN;


            // add up variable-len portions (multiply by 2 for byte len of char strings)
            //
            length += (rec.HostName.Length + rec.ApplicationName.Length +
                       rec.ServerName.Length + clientInterfaceName.Length +
                       rec.Language.Length + rec.Database.Length +
                       rec.AttachDbFilename.Length) * 2;
            if (useFeatureExt)
            {
                length += 4;
            }

            // allocate memory for SSPI variables

            // only add lengths of password and username if not using SSPI

            var userName          = "";
            var encryptedPassword = new byte[0];

            if (rec.UseSspi)
            {
                length += rec.ClientToken.Length;
            }
            else
            {
                userName          = rec.UserName;
                encryptedPassword = ObfuscatePassword(rec.Password);
                length           += userName.Length * 2 + encryptedPassword.Length;
            }

            var feOffset = length;

            if (useFeatureExt)
            {
                if ((requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0)
                {
                    length += SessionRecoveryFeatureRequestLengths(recoverySessionData).totalLength;
                }
                if ((requestedFeatures & TdsEnums.FeatureExtension.GlobalTransactions) != 0)
                {
                    length += 5;
                }
                length++; // for terminator
            }

            writer.NewPackage(TdsEnums.MT_LOGIN7);
            writer.WriteInt32(length);
            if (recoverySessionData == null)
            {
                writer.WriteInt32((TdsEnums.DENALI_MAJOR << 24) | (TdsEnums.DENALI_INCREMENT << 16) | TdsEnums.DENALI_MINOR);
            }
            else
            {
                writer.WriteUInt32(recoverySessionData.TdsVersion);
            }
            writer.WriteInt32(rec.PacketSize);
            writer.WriteInt32(TdsEnums.CLIENT_PROG_VER);
            writer.WriteInt32(GetCurrentProcessIdForTdsLoginOnly());
            writer.WriteInt32(0); // connectionID is unused

            // Log7Flags (DWORD)
            var log7Flags = 0;

            /*
             * Current snapshot from TDS spec with the offsets added:
             *  0) fByteOrder:1,                // byte order of numeric data types on client
             *  1) fCharSet:1,                  // character set on client
             *  2) fFloat:2,                    // Type of floating point on client
             *  4) fDumpLoad:1,                 // Dump/Load and BCP enable
             *  5) fUseDb:1,                    // USE notification
             *  6) fDatabase:1,                 // Initial database fatal flag
             *  7) fSetLang:1,                  // SET LANGUAGE notification
             *  8) fLanguage:1,                 // Initial language fatal flag
             *  9) fODBC:1,                     // Set if client is ODBC driver
             * 10) fTranBoundary:1,             // Transaction boundary notification
             * 11) fDelegatedSec:1,             // Security with delegation is available
             * 12) fUserType:3,                 // Type of user
             * 15) fIntegratedSecurity:1,       // Set if client is using integrated security
             * 16) fSQLType:4,                  // Type of SQL sent from client
             * 20) fOLEDB:1,                    // Set if client is OLEDB driver
             * 21) fSpare1:3,                   // first bit used for read-only intent, rest unused
             * 24) fResetPassword:1,            // set if client wants to reset password
             * 25) fNoNBCAndSparse:1,           // set if client does not support NBC and Sparse column
             * 26) fUserInstance:1,             // This connection wants to connect to a SQL "user instance"
             * 27) fUnknownCollationHandling:1, // This connection can handle unknown collation correctly.
             * 28) fExtension:1                 // Extensions are used
             * 32 - total
             */

            // first byte
            log7Flags |= TdsEnums.USE_DB_ON << 5;
            log7Flags |= TdsEnums.INIT_DB_FATAL << 6;
            log7Flags |= TdsEnums.SET_LANG_ON << 7;

            // second byte
            log7Flags |= TdsEnums.INIT_LANG_FATAL << 8;
            log7Flags |= TdsEnums.ODBC_ON << 9;
            if (rec.UseReplication)
            {
                log7Flags |= TdsEnums.REPL_ON << 12;
            }
            if (rec.UseSspi)
            {
                log7Flags |= TdsEnums.SSPI_ON << 15;
            }

            // third byte
            if (rec.ReadOnlyIntent)
            {
                log7Flags |= TdsEnums.READONLY_INTENT_ON << 21;                     // read-only intent flag is a first bit of fSpare1
            }
            // 4th one
            if (rec.UserInstance)
            {
                log7Flags |= 1 << 26;
            }
            if (useFeatureExt)
            {
                log7Flags |= 1 << 28;
            }

            writer.WriteInt32(log7Flags);

            writer.WriteInt32(0); // ClientTimeZone is not used
            writer.WriteInt32(0); // LCID is unused by server

            // Start writing offset and length of variable length portions
            var offset = TdsEnums.YUKON_LOG_REC_FIXED_LEN;

            // write offset/length pairs

            // note that you must always set ibHostName since it indicates the beginning of the variable length section of the login record
            writer.WriteInt16(offset); // host name offset
            writer.WriteInt16(rec.HostName.Length);
            offset += rec.HostName.Length * 2;

            // Only send user/password over if not fSSPI...  If both user/password and SSPI are in login
            // rec, only SSPI is used.  Confirmed same behavior as in luxor.
            if (rec.UseSspi)
            {
                // case where user/password data is not used, send over zeros
                writer.WriteInt16(0); // userName offset
                writer.WriteInt16(0);
                writer.WriteInt16(0); // password offset
                writer.WriteInt16(0);
            }
            else
            {
                writer.WriteInt16(offset); // userName offset
                writer.WriteInt16(userName.Length);
                offset += userName.Length * 2;

                // the encrypted password is a byte array - so length computations different than strings
                writer.WriteInt16(offset); // password offset
                writer.WriteInt16(encryptedPassword.Length / 2);
                offset += encryptedPassword.Length;
            }

            writer.WriteInt16(offset); // app name offset
            writer.WriteInt16(rec.ApplicationName.Length);
            offset += rec.ApplicationName.Length * 2;

            writer.WriteInt16(offset); // server name offset
            writer.WriteInt16(rec.ServerName.Length);
            offset += rec.ServerName.Length * 2;

            writer.WriteInt16(offset);
            if (useFeatureExt)
            {
                writer.WriteInt16(4); // length of ibFeatgureExtLong (which is a DWORD)
                offset += 4;
            }
            else
            {
                writer.WriteInt16(0); // unused (was remote password ?)
            }

            writer.WriteInt16(offset); // client interface name offset
            writer.WriteInt16(clientInterfaceName.Length);
            offset += clientInterfaceName.Length * 2;

            writer.WriteInt16(offset); // language name offset
            writer.WriteInt16(rec.Language.Length);
            offset += rec.Language.Length * 2;

            writer.WriteInt16(offset); // database name offset
            writer.WriteInt16(rec.Database.Length);
            offset += rec.Database.Length * 2;

            var nicAddress = GetNetworkPhysicalAddressForTdsLoginOnly();

            writer.WriteByteArray(nicAddress);

            writer.WriteInt16(offset); // ibSSPI offset
            if (rec.UseSspi)
            {
                writer.WriteInt16(rec.ClientToken.Length);
                offset += rec.ClientToken.Length;
            }
            else
            {
                writer.WriteInt16(0);
            }

            writer.WriteInt16(offset); // DB filename offset
            writer.WriteInt16(rec.AttachDbFilename.Length);
            offset += rec.AttachDbFilename.Length * 2;

            writer.WriteInt16(offset); // reset password offset
            writer.WriteInt16(0);

            writer.WriteInt32(0); // reserved for chSSPI

            // write variable length portion
            writer.WriteUnicodeString(rec.HostName);

            // if we are using SSPI, do not send over username/password, since we will use SSPI instead
            // same behavior as Luxor
            if (!rec.UseSspi)
            {
                writer.WriteUnicodeString(userName);
                writer.WriteByteArray(encryptedPassword);
            }

            writer.WriteUnicodeString(rec.ApplicationName);
            writer.WriteUnicodeString(rec.ServerName);

            // write ibFeatureExtLong
            if (useFeatureExt)
            {
                writer.WriteInt32(feOffset);
            }

            writer.WriteUnicodeString(clientInterfaceName);
            writer.WriteUnicodeString(rec.Language);
            writer.WriteUnicodeString(rec.Database);

            // send over SSPI data if we are using SSPI
            if (rec.UseSspi)
            {
                writer.WriteByteArray(rec.ClientToken);
            }

            writer.WriteUnicodeString(rec.AttachDbFilename);
            if (useFeatureExt)
            {
                if ((requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0)
                {
                    WriteSessionRecoveryFeatureRequest(writer, recoverySessionData);
                }
                if ((requestedFeatures & TdsEnums.FeatureExtension.GlobalTransactions) != 0)
                {
                    WriteGlobalTransactionsFeatureRequest(writer);
                }
                writer.WriteByte(0xFF); // terminator
            }
        }
示例#30
0
 internal static void WriteGlobalTransactionsFeatureRequest(TdsPackageWriter writer)
 {
     // Write Feature ID
     writer.WriteByte(TdsEnums.FEATUREEXT_GLOBALTRANSACTIONS);
     writer.WriteInt32(0); // we don't send any data
 }