Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / TdsParserStaticMethods.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="TdsParserStaticFunctionality.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data.SqlClient {
10     using System;
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;
21     using System.Text;
22     using System.Threading;
23     using System.Runtime.Versioning;
24
25     internal sealed class TdsParserStaticMethods {
26
27         private TdsParserStaticMethods() { /* prevent utility class from being insantiated*/ }
28         //
29         // Static methods
30         //
31
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) {
36 #if !MOBILE
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".
44
45                         supported formats:
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]
50                             sm - DBMSLPCN,server
51
52                         unsupported formats:
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]
57                     */
58                     // We must parse into the two component pieces, then map the first protocol piece to the
59                     // appropriate value.
60                     int index = aliasLookup.IndexOf(',');
61
62                     // If we found the key, but there was no "," in the string, it is a bad Alias so return.
63                     if (-1 != index) {
64                         string parsedProtocol = aliasLookup.Substring(0, index).ToLower(CultureInfo.InvariantCulture);
65
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);
69
70                             // Fix bug 298286
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);
78                                         }
79                                     }
80                                 }
81                             else {
82                                     protocol = (string)SqlConnectionString.NetlibMapping()[parsedProtocol];
83                                     if (null != protocol) {
84                                         host = parsedAliasName;
85                                 }
86                             }
87                         }
88                     }
89                 }
90             }
91 #endif
92         }
93
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];
99             int s;
100             byte bLo;
101             byte bHi;
102
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);
109             }
110             return bEnc;
111         }
112
113         [ResourceExposure(ResourceScope.None)] // SxS: we use this method for TDS login only
114         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
115         static internal int GetCurrentProcessIdForTdsLoginOnly() {
116 #if MOBILE
117             return 0;
118 #else
119             return SafeNativeMethods.GetCurrentProcessId();
120 #endif
121         }
122
123
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
131         }
132
133
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.
144
145             const string key        = "NetworkAddress";
146             const string localKey   = "NetworkAddressLocal";
147             const string folder     = "SOFTWARE\\Description\\Microsoft\\Rpc\\UuidTemporaryData";
148
149             int result = 0;
150             byte[] nicAddress = null;
151
152             object temp = ADP.LocalMachineRegistryValue(folder, localKey);
153             if (temp is int) {
154                 result = (int) temp;
155             }
156
157             if (result <= 0) {
158                 temp = ADP.LocalMachineRegistryValue(folder, key);
159                 if (temp is byte[]) {
160                     nicAddress = (byte[]) temp;
161                 }
162             }
163
164             if (null == nicAddress) {
165                 nicAddress = new byte[TdsEnums.MAX_NIC_SIZE];
166                 Random random = new Random();
167                 random.NextBytes(nicAddress);
168             }
169
170             return nicAddress;
171         }
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
179
180             if (Int64.MaxValue == timeoutTime) {
181                 return -1;  // infinite timeout
182             }
183
184             long msecRemaining = ADP.TimerRemainingMilliseconds(timeoutTime);
185
186             if (msecRemaining < 0) {
187                 return 0;
188             }
189             if (msecRemaining > (long)Int32.MaxValue) {
190                 return Int32.MaxValue;
191             }
192             return (Int32)msecRemaining;
193         }
194
195         static internal long GetTimeoutSeconds(int timeout) {
196             return GetTimeout((long)timeout * 1000L);
197         }
198
199         static internal long GetTimeout(long timeoutMilliseconds) {
200             long result;
201             if (timeoutMilliseconds <= 0) {
202                 result = Int64.MaxValue; // no timeout...
203             }
204             else {
205                 try
206                 {
207                     result = checked(ADP.TimerCurrent() + ADP.TimerFromMilliseconds(timeoutMilliseconds));
208                 }
209                 catch (OverflowException)
210                 {
211                     // In case of overflow, set to 'infinite' timeout
212                     result = Int64.MaxValue;
213                 }
214             }
215             return result;
216         }
217
218         static internal bool TimeoutHasExpired(long timeoutTime) {
219             bool result = false;
220
221             if (0 != timeoutTime && Int64.MaxValue != timeoutTime) {
222                 result = ADP.TimerHasExpired(timeoutTime);
223             }
224             return result;
225         }
226
227         static internal int NullAwareStringLength(string str) {
228             if (str == null) {
229                 return 0;
230             }
231             else {
232                 return str.Length;
233             }
234         }
235
236         static internal int GetRemainingTimeout(int timeout, long start) {
237             if (timeout <= 0) {
238                 return timeout;
239             }
240             long remaining = ADP.TimerRemainingSeconds(start + ADP.TimerFromSeconds(timeout));
241             if (remaining <= 0) {
242                 return 1;
243             }
244             else {
245                 return checked((int)remaining);
246             }
247         }
248
249     }
250 }