1 //------------------------------------------------------------------------------
2 // <copyright file="TdsParserStaticFunctionality.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 namespace System
.Data
.SqlClient
{
11 using System
.Data
.Common
;
12 using System
.Data
.ProviderBase
;
13 using System
.Data
.Sql
;
14 using System
.Data
.SqlTypes
;
15 using System
.Diagnostics
;
16 using System
.Globalization
;
17 using System
.Runtime
.CompilerServices
;
18 using System
.Runtime
.InteropServices
;
19 using System
.Security
;
20 using System
.Security
.Permissions
;
22 using System
.Threading
;
23 using System
.Runtime
.Versioning
;
25 internal sealed class TdsParserStaticMethods
{
27 private TdsParserStaticMethods() { /* prevent utility class from being insantiated*/ }
32 // SxS: this method accesses registry to resolve the alias.
33 [ResourceExposure(ResourceScope
.None
)]
34 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
35 static internal void AliasRegistryLookup(ref string host
, ref string protocol
) {
37 if (!ADP
.IsEmpty(host
)) {
38 const String folder
= "SOFTWARE\\Microsoft\\MSSQLServer\\Client\\ConnectTo";
39 // Put a try...catch... around this so we don't abort ANY connection if we can't read the registry.
40 string aliasLookup
= (string) ADP
.LocalMachineRegistryValue(folder
, host
);
41 if (!ADP
.IsEmpty(aliasLookup
)) {
42 /* Result will be in the form of: "DBNMPNTW,\\blained1\pipe\sql\query". or
43 Result will be in the form of: "DBNETLIB, via:\\blained1\pipe\sql\query".
46 tcp - DBMSSOCN,[server|server\instance][,port]
47 np - DBNMPNTW,[\\server\pipe\sql\query | \\server\pipe\MSSQL$instance\sql\query]
48 where \sql\query is the pipename and can be replaced with any other pipe name
49 via - [DBMSGNET,server,port | DBNETLIB, via:server, port]
53 rpc - DBMSRPCN,server,[parameters] where parameters could be "username,password"
54 bv - DBMSVINN,service@group@organization
55 appletalk - DBMSADSN,objectname@zone
56 spx - DBMSSPXN,[service | address,port,network]
58 // We must parse into the two component pieces, then map the first protocol piece to the
60 int index
= aliasLookup
.IndexOf(',');
62 // If we found the key, but there was no "," in the string, it is a bad Alias so return.
64 string parsedProtocol
= aliasLookup
.Substring(0, index
).ToLower(CultureInfo
.InvariantCulture
);
66 // If index+1 >= length, Alias consisted of "FOO," which is a bad alias so return.
67 if (index
+1 < aliasLookup
.Length
) {
68 string parsedAliasName
= aliasLookup
.Substring(index
+1);
71 if ("dbnetlib" == parsedProtocol
) {
72 index
= parsedAliasName
.IndexOf(':');
73 if (-1 != index
&& index
+ 1 < parsedAliasName
.Length
) {
74 parsedProtocol
= parsedAliasName
.Substring (0, index
);
75 if (SqlConnectionString
.ValidProtocal (parsedProtocol
)) {
76 protocol
= parsedProtocol
;
77 host
= parsedAliasName
.Substring(index
+ 1);
82 protocol
= (string)SqlConnectionString
.NetlibMapping()[parsedProtocol
];
83 if (null != protocol
) {
84 host
= parsedAliasName
;
94 // Encrypt password to be sent to SQL Server
95 // Note: The same logic is used in SNIPacketSetData (SniManagedWrapper) to encrypt passwords stored in SecureString
96 // If this logic changed, SNIPacketSetData needs to be changed as well
97 static internal Byte
[] EncryptPassword(string password
) {
98 Byte
[] bEnc
= new Byte
[password
.Length
<< 1];
103 for (int i
= 0; i
< password
.Length
; i
++) {
104 s
= (int) password
[i
];
105 bLo
= (byte) (s
& 0xff);
106 bHi
= (byte) ((s
>> 8) & 0xff);
107 bEnc
[i
<<1] = (Byte
) ( (((bLo
& 0x0f) << 4) | (bLo
>> 4)) ^
0xa5 );
108 bEnc
[(i
<<1)+1] = (Byte
) ( (((bHi
& 0x0f) << 4) | (bHi
>> 4)) ^
0xa5);
113 [ResourceExposure(ResourceScope
.None
)] // SxS: we use this method for TDS login only
114 [ResourceConsumption(ResourceScope
.Process
, ResourceScope
.Process
)]
115 static internal int GetCurrentProcessIdForTdsLoginOnly() {
119 return SafeNativeMethods
.GetCurrentProcessId();
124 [SecurityPermission(SecurityAction
.Assert
, Flags
= SecurityPermissionFlag
.UnmanagedCode
)]
125 [ResourceExposure(ResourceScope
.None
)] // SxS: we use this method for TDS login only
126 [ResourceConsumption(ResourceScope
.Process
, ResourceScope
.Process
)]
127 static internal Int32
GetCurrentThreadIdForTdsLoginOnly() {
128 #pragma warning disable 618
129 return AppDomain
.GetCurrentThreadId(); // don't need this to be support fibres;
130 #pragma warning restore 618
134 [ResourceExposure(ResourceScope
.None
)] // SxS: we use MAC address for TDS login only
135 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
136 static internal byte[] GetNetworkPhysicalAddressForTdsLoginOnly() {
137 // NIC address is stored in NetworkAddress key. However, if NetworkAddressLocal key
138 // has a value that is not zero, then we cannot use the NetworkAddress key and must
139 // instead generate a random one. I do not fully understand why, this is simply what
140 // the native providers do. As for generation, I use a random number generator, which
141 // means that different processes on the same machine will have different NIC address
142 // values on the server. It is not ideal, but native does not have the same value for
143 // different processes either.
145 const string key
= "NetworkAddress";
146 const string localKey
= "NetworkAddressLocal";
147 const string folder
= "SOFTWARE\\Description\\Microsoft\\Rpc\\UuidTemporaryData";
150 byte[] nicAddress
= null;
152 object temp
= ADP
.LocalMachineRegistryValue(folder
, localKey
);
158 temp
= ADP
.LocalMachineRegistryValue(folder
, key
);
159 if (temp
is byte[]) {
160 nicAddress
= (byte[]) temp
;
164 if (null == nicAddress
) {
165 nicAddress
= new byte[TdsEnums
.MAX_NIC_SIZE
];
166 Random random
= new Random();
167 random
.NextBytes(nicAddress
);
172 // translates remaining time in stateObj (from user specified timeout) to timout value for SNI
173 static internal Int32
GetTimeoutMilliseconds(long timeoutTime
) {
174 // User provided timeout t | timeout value for SNI | meaning
175 // ------------------------+-----------------------+------------------------------
176 // t == long.MaxValue | -1 | infinite timeout (no timeout)
177 // t>0 && t<int.MaxValue | t |
178 // t>int.MaxValue | int.MaxValue | must not exceed int.MaxValue
180 if (Int64
.MaxValue
== timeoutTime
) {
181 return -1; // infinite timeout
184 long msecRemaining
= ADP
.TimerRemainingMilliseconds(timeoutTime
);
186 if (msecRemaining
< 0) {
189 if (msecRemaining
> (long)Int32
.MaxValue
) {
190 return Int32
.MaxValue
;
192 return (Int32
)msecRemaining
;
195 static internal long GetTimeoutSeconds(int timeout
) {
196 return GetTimeout((long)timeout
* 1000L);
199 static internal long GetTimeout(long timeoutMilliseconds
) {
201 if (timeoutMilliseconds
<= 0) {
202 result
= Int64
.MaxValue
; // no timeout...
207 result
= checked(ADP
.TimerCurrent() + ADP
.TimerFromMilliseconds(timeoutMilliseconds
));
209 catch (OverflowException
)
211 // In case of overflow, set to 'infinite' timeout
212 result
= Int64
.MaxValue
;
218 static internal bool TimeoutHasExpired(long timeoutTime
) {
221 if (0 != timeoutTime
&& Int64
.MaxValue
!= timeoutTime
) {
222 result
= ADP
.TimerHasExpired(timeoutTime
);
227 static internal int NullAwareStringLength(string str
) {
236 static internal int GetRemainingTimeout(int timeout
, long start
) {
240 long remaining
= ADP
.TimerRemainingSeconds(start
+ ADP
.TimerFromSeconds(timeout
));
241 if (remaining
<= 0) {
245 return checked((int)remaining
);