TdsParserHelperClasses.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. //------------------------------------------------------------------------------
  2. // <copyright file="TdsParserHelperClasses.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. namespace System.Data.SqlClient {
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Data;
  12. using System.Data.Common;
  13. using System.Data.ProviderBase;
  14. using System.Data.Sql;
  15. using System.Data.SqlTypes;
  16. using System.Diagnostics;
  17. using System.Reflection;
  18. using System.Text;
  19. using System.Threading;
  20. using System.Security;
  21. using System.Globalization;
  22. using Microsoft.SqlServer.Server; // for SMI metadata
  23. internal enum CallbackType {
  24. Read = 0,
  25. Write = 1
  26. }
  27. internal enum EncryptionOptions {
  28. OFF,
  29. ON,
  30. NOT_SUP,
  31. REQ,
  32. LOGIN
  33. }
  34. internal enum PreLoginHandshakeStatus {
  35. Successful,
  36. InstanceFailure
  37. }
  38. internal enum PreLoginOptions {
  39. VERSION,
  40. ENCRYPT,
  41. INSTANCE,
  42. THREADID,
  43. MARS,
  44. TRACEID,
  45. FEDAUTHREQUIRED,
  46. NUMOPT,
  47. LASTOPT = 255
  48. }
  49. internal enum RunBehavior {
  50. UntilDone = 1, // 0001 binary
  51. ReturnImmediately = 2, // 0010 binary
  52. Clean = 5, // 0101 binary - Clean AND UntilDone
  53. Attention = 13 // 1101 binary - Clean AND UntilDone AND Attention
  54. }
  55. internal enum TdsParserState {
  56. Closed,
  57. OpenNotLoggedIn,
  58. OpenLoggedIn,
  59. Broken,
  60. }
  61. /// <summary>
  62. /// Struct encapsulating the data to be sent to the server as part of Federated Authentication Feature Extension.
  63. /// </summary>
  64. internal struct FederatedAuthenticationFeatureExtensionData
  65. {
  66. internal TdsEnums.FedAuthLibrary libraryType;
  67. internal bool fedAuthRequiredPreLoginResponse;
  68. internal SqlAuthenticationMethod authentication;
  69. internal byte[] accessToken;
  70. }
  71. /// <summary>
  72. /// <para> Represents a single encrypted value for a CEK. It contains the encrypted CEK,
  73. /// the store type, name,the key path and encryption algorithm.</para>
  74. /// </summary>
  75. internal struct SqlEncryptionKeyInfo {
  76. internal byte[] encryptedKey; // the encrypted "column encryption key"
  77. internal int databaseId;
  78. internal int cekId;
  79. internal int cekVersion;
  80. internal byte[] cekMdVersion;
  81. internal string keyPath;
  82. internal string keyStoreName;
  83. internal string algorithmName;
  84. internal byte normalizationRuleVersion;
  85. }
  86. /// <summary>
  87. /// <para> Encapsulates one entry in the CipherInfo table sent as part of Colmetadata.
  88. /// The same CEK is encrypted multiple times with different master keys (for master key
  89. /// rotation scenario) We need to keep all these around until we can resolve the CEK
  90. /// using the correct master key.</para>
  91. /// </summary>
  92. internal struct SqlTceCipherInfoEntry {
  93. /// <summary>
  94. /// List of Column Encryption Key Information.
  95. /// </summary>
  96. private readonly List<SqlEncryptionKeyInfo> _columnEncryptionKeyValues;
  97. /// <summary>
  98. /// Key Ordinal.
  99. /// </summary>
  100. private readonly int _ordinal;
  101. /// <summary>
  102. /// Database ID
  103. /// </summary>
  104. private int _databaseId;
  105. /// <summary>
  106. /// Cek ID
  107. /// </summary>
  108. private int _cekId;
  109. /// <summary>
  110. /// Cek Version
  111. /// </summary>
  112. private int _cekVersion;
  113. /// <summary>
  114. /// Cek MD Version
  115. /// </summary>
  116. private byte[] _cekMdVersion;
  117. /// <summary>
  118. /// Return the ordinal.
  119. /// </summary>
  120. internal int Ordinal {
  121. get {
  122. return _ordinal;
  123. }
  124. }
  125. /// <summary>
  126. /// Return the DatabaseID.
  127. /// </summary>
  128. internal int DatabaseId {
  129. get {
  130. return _databaseId;
  131. }
  132. }
  133. /// <summary>
  134. /// Return the CEK ID.
  135. /// </summary>
  136. internal int CekId {
  137. get {
  138. return _cekId;
  139. }
  140. }
  141. /// <summary>
  142. /// Return the CEK Version.
  143. /// </summary>
  144. internal int CekVersion {
  145. get {
  146. return _cekVersion;
  147. }
  148. }
  149. /// <summary>
  150. /// Return the CEK MD Version.
  151. /// </summary>
  152. internal byte[] CekMdVersion {
  153. get {
  154. return _cekMdVersion;
  155. }
  156. }
  157. /// <summary>
  158. /// Return the list of Column Encryption Key Values.
  159. /// </summary>
  160. internal List<SqlEncryptionKeyInfo> ColumnEncryptionKeyValues {
  161. get {
  162. return _columnEncryptionKeyValues;
  163. }
  164. }
  165. /// <summary>
  166. /// Add an entry to the list of ColumnEncryptionKeyValues.
  167. /// </summary>
  168. /// <param name="encryptedKey"></param>
  169. /// <param name="databaseId"></param>
  170. /// <param name="cekId"></param>
  171. /// <param name="cekVersion"></param>
  172. /// <param name="cekMdVersion"></param>
  173. /// <param name="keyPath"></param>
  174. /// <param name="keyStoreName"></param>
  175. /// <param name="algorithmName"></param>
  176. internal void Add(byte[] encryptedKey, int databaseId, int cekId, int cekVersion, byte[] cekMdVersion, string keyPath, string keyStoreName, string algorithmName) {
  177. Debug.Assert(_columnEncryptionKeyValues != null, "_columnEncryptionKeyValues should already be initialized.");
  178. SqlEncryptionKeyInfo encryptionKey = new SqlEncryptionKeyInfo();
  179. encryptionKey.encryptedKey = encryptedKey;
  180. encryptionKey.databaseId = databaseId;
  181. encryptionKey.cekId = cekId;
  182. encryptionKey.cekVersion = cekVersion;
  183. encryptionKey.cekMdVersion = cekMdVersion;
  184. encryptionKey.keyPath = keyPath;
  185. encryptionKey.keyStoreName = keyStoreName;
  186. encryptionKey.algorithmName = algorithmName;
  187. _columnEncryptionKeyValues.Add(encryptionKey);
  188. if (0 == _databaseId) {
  189. _databaseId = databaseId;
  190. _cekId = cekId;
  191. _cekVersion = cekVersion;
  192. _cekMdVersion = cekMdVersion;
  193. }
  194. else {
  195. Debug.Assert(_databaseId == databaseId);
  196. Debug.Assert(_cekId == cekId);
  197. Debug.Assert(_cekVersion == cekVersion);
  198. Debug.Assert (_cekMdVersion != null && cekMdVersion != null && _cekMdVersion.Length == _cekMdVersion.Length);
  199. }
  200. }
  201. /// <summary>
  202. /// Constructor.
  203. /// </summary>
  204. /// <param name="ordinal"></param>
  205. internal SqlTceCipherInfoEntry(int ordinal = 0) : this() {
  206. _ordinal = ordinal;
  207. _databaseId = 0;
  208. _cekId = 0;
  209. _cekVersion = 0;
  210. _cekMdVersion = null;
  211. _columnEncryptionKeyValues = new List<SqlEncryptionKeyInfo>();
  212. }
  213. }
  214. /// <summary>
  215. /// <para> Represents a table with various CEKs used in a resultset. Each entry corresponds to one (unique) CEK. The CEK
  216. /// may have been encrypted using multiple master keys (giving us multiple CEK values). All these values form one single
  217. /// entry in this table.</para>
  218. ///</summary>
  219. internal struct SqlTceCipherInfoTable {
  220. private readonly SqlTceCipherInfoEntry [] keyList;
  221. internal SqlTceCipherInfoTable (int tabSize) {
  222. Debug.Assert (0 < tabSize, "Invalid Table Size");
  223. keyList = new SqlTceCipherInfoEntry[tabSize];
  224. }
  225. internal SqlTceCipherInfoEntry this [int index] {
  226. get {
  227. Debug.Assert (index < keyList.Length, "Invalid index specified.");
  228. return keyList[index];
  229. }
  230. set {
  231. Debug.Assert (index < keyList.Length, "Invalid index specified.");
  232. keyList[index] = value;
  233. }
  234. }
  235. internal int Size {
  236. get {
  237. return keyList.Length;
  238. }
  239. }
  240. }
  241. sealed internal class SqlCollation {
  242. // First 20 bits of info field represent the lcid, bits 21-25 are compare options
  243. private const uint IgnoreCase = 1 << 20; // bit 21 - IgnoreCase
  244. private const uint IgnoreNonSpace = 1 << 21; // bit 22 - IgnoreNonSpace / IgnoreAccent
  245. private const uint IgnoreWidth = 1 << 22; // bit 23 - IgnoreWidth
  246. private const uint IgnoreKanaType = 1 << 23; // bit 24 - IgnoreKanaType
  247. private const uint BinarySort = 1 << 24; // bit 25 - BinarySort
  248. internal const uint MaskLcid = 0xfffff;
  249. private const int LcidVersionBitOffset = 28;
  250. private const uint MaskLcidVersion = unchecked((uint)(0xf << LcidVersionBitOffset));
  251. private const uint MaskCompareOpt = IgnoreCase | IgnoreNonSpace | IgnoreWidth | IgnoreKanaType | BinarySort;
  252. internal uint info;
  253. internal byte sortId;
  254. static int FirstSupportedCollationVersion(int lcid)
  255. {
  256. // NOTE: switch-case works ~3 times faster in this case than search with Dictionary
  257. switch (lcid)
  258. {
  259. case 1044: return 2; // Norwegian_100_BIN
  260. case 1047: return 2; // Romansh_100_BIN
  261. case 1056: return 2; // Urdu_100_BIN
  262. case 1065: return 2; // Persian_100_BIN
  263. case 1068: return 2; // Azeri_Latin_100_BIN
  264. case 1070: return 2; // Upper_Sorbian_100_BIN
  265. case 1071: return 1; // ----n_FYROM_90_BIN
  266. case 1081: return 1; // Indic_General_90_BIN
  267. case 1082: return 2; // Maltese_100_BIN
  268. case 1083: return 2; // Sami_Norway_100_BIN
  269. case 1087: return 1; // Kazakh_90_BIN
  270. case 1090: return 2; // Turkmen_100_BIN
  271. case 1091: return 1; // Uzbek_Latin_90_BIN
  272. case 1092: return 1; // Tatar_90_BIN
  273. case 1093: return 2; // Bengali_100_BIN
  274. case 1101: return 2; // Assamese_100_BIN
  275. case 1105: return 2; // Tibetan_100_BIN
  276. case 1106: return 2; // Welsh_100_BIN
  277. case 1107: return 2; // Khmer_100_BIN
  278. case 1108: return 2; // Lao_100_BIN
  279. case 1114: return 1; // Syriac_90_BIN
  280. case 1121: return 2; // Nepali_100_BIN
  281. case 1122: return 2; // Frisian_100_BIN
  282. case 1123: return 2; // Pashto_100_BIN
  283. case 1125: return 1; // Divehi_90_BIN
  284. case 1133: return 2; // Bashkir_100_BIN
  285. case 1146: return 2; // Mapudungan_100_BIN
  286. case 1148: return 2; // Mohawk_100_BIN
  287. case 1150: return 2; // Breton_100_BIN
  288. case 1152: return 2; // Uighur_100_BIN
  289. case 1153: return 2; // Maori_100_BIN
  290. case 1155: return 2; // Corsican_100_BIN
  291. case 1157: return 2; // Yakut_100_BIN
  292. case 1164: return 2; // Dari_100_BIN
  293. case 2074: return 2; // Serbian_Latin_100_BIN
  294. case 2092: return 2; // Azeri_Cyrillic_100_BIN
  295. case 2107: return 2; // Sami_Sweden_Finland_100_BIN
  296. case 2143: return 2; // Tamazight_100_BIN
  297. case 3076: return 1; // Chinese_Hong_Kong_Stroke_90_BIN
  298. case 3098: return 2; // Serbian_Cyrillic_100_BIN
  299. case 5124: return 2; // Chinese_Traditional_Pinyin_100_BIN
  300. case 5146: return 2; // Bosnian_Latin_100_BIN
  301. case 8218: return 2; // Bosnian_Cyrillic_100_BIN
  302. default: return 0; // other LCIDs have collation with version 0
  303. }
  304. }
  305. internal int LCID {
  306. // First 20 bits of info field represent the lcid
  307. get {
  308. return unchecked((int)(info & MaskLcid));
  309. }
  310. set {
  311. int lcid = value & (int)MaskLcid;
  312. Debug.Assert(lcid == value, "invalid set_LCID value");
  313. // VSTFDEVDIV 479474: some new Katmai LCIDs do not have collation with version = 0
  314. // since user has no way to specify collation version, we set the first (minimal) supported version for these collations
  315. int versionBits = FirstSupportedCollationVersion(lcid) << LcidVersionBitOffset;
  316. Debug.Assert((versionBits & MaskLcidVersion) == versionBits, "invalid version returned by FirstSupportedCollationVersion");
  317. // combine the current compare options with the new locale ID and its first supported version
  318. info = (info & MaskCompareOpt) | unchecked((uint)lcid) | unchecked((uint)versionBits);
  319. }
  320. }
  321. internal SqlCompareOptions SqlCompareOptions {
  322. get {
  323. SqlCompareOptions options = SqlCompareOptions.None;
  324. if (0 != (info & IgnoreCase))
  325. options |= SqlCompareOptions.IgnoreCase;
  326. if (0 != (info & IgnoreNonSpace))
  327. options |= SqlCompareOptions.IgnoreNonSpace;
  328. if (0 != (info & IgnoreWidth))
  329. options |= SqlCompareOptions.IgnoreWidth;
  330. if (0 != (info & IgnoreKanaType))
  331. options |= SqlCompareOptions.IgnoreKanaType;
  332. if (0 != (info & BinarySort))
  333. options |= SqlCompareOptions.BinarySort;
  334. return options;
  335. }
  336. set {
  337. Debug.Assert((value & SqlString.x_iValidSqlCompareOptionMask) == value, "invalid set_SqlCompareOptions value");
  338. uint tmp = 0;
  339. if (0 != (value & SqlCompareOptions.IgnoreCase))
  340. tmp |= IgnoreCase;
  341. if (0 != (value & SqlCompareOptions.IgnoreNonSpace))
  342. tmp |= IgnoreNonSpace;
  343. if (0 != (value & SqlCompareOptions.IgnoreWidth))
  344. tmp |= IgnoreWidth;
  345. if (0 != (value & SqlCompareOptions.IgnoreKanaType))
  346. tmp |= IgnoreKanaType;
  347. if (0 != (value & SqlCompareOptions.BinarySort))
  348. tmp |= BinarySort;
  349. info = (info & MaskLcid) | tmp;
  350. }
  351. }
  352. internal string TraceString() {
  353. return String.Format(/*IFormatProvider*/ null, "(LCID={0}, Opts={1})", this.LCID, (int)this.SqlCompareOptions);
  354. }
  355. static internal bool AreSame(SqlCollation a, SqlCollation b) {
  356. if (a == null || b == null) {
  357. return a == b;
  358. }
  359. else {
  360. return a.info == b.info && a.sortId == b.sortId;
  361. }
  362. }
  363. }
  364. internal class RoutingInfo {
  365. internal byte Protocol { get; private set; }
  366. internal UInt16 Port { get; private set; }
  367. internal string ServerName { get; private set; }
  368. internal RoutingInfo(byte protocol, UInt16 port, string servername) {
  369. Protocol = protocol;
  370. Port = port;
  371. ServerName = servername;
  372. }
  373. }
  374. sealed internal class SqlEnvChange {
  375. internal byte type;
  376. internal byte oldLength;
  377. internal int newLength; // 7206 TDS changes makes this length an int
  378. internal int length;
  379. internal string newValue;
  380. internal string oldValue;
  381. internal byte[] newBinValue;
  382. internal byte[] oldBinValue;
  383. internal long newLongValue;
  384. internal long oldLongValue;
  385. internal SqlCollation newCollation;
  386. internal SqlCollation oldCollation;
  387. internal RoutingInfo newRoutingInfo;
  388. }
  389. sealed internal class SqlLogin {
  390. internal SqlAuthenticationMethod authentication = SqlAuthenticationMethod.NotSpecified; // Authentication type
  391. internal int timeout; // login timeout
  392. internal bool userInstance = false; // user instance
  393. internal string hostName = ""; // client machine name
  394. internal string userName = ""; // user id
  395. internal string password = ""; // password
  396. internal string applicationName = ""; // application name
  397. internal string serverName = ""; // server name
  398. internal string language = ""; // initial language
  399. internal string database = ""; // initial database
  400. internal string attachDBFilename = ""; // DB filename to be attached
  401. internal string newPassword = ""; // new password for reset password
  402. internal bool useReplication = false; // user login for replication
  403. internal bool useSSPI = false; // use integrated security
  404. internal int packetSize = SqlConnectionString.DEFAULT.Packet_Size; // packet size
  405. internal bool readOnlyIntent = false; // read-only intent
  406. internal SqlCredential credential; // user id and password in SecureString
  407. internal SecureString newSecurePassword; // new password in SecureString for resetting pasword
  408. }
  409. sealed internal class SqlLoginAck {
  410. internal string programName;
  411. internal byte majorVersion;
  412. internal byte minorVersion;
  413. internal short buildNum;
  414. internal bool isVersion8;
  415. internal UInt32 tdsVersion;
  416. }
  417. sealed internal class SqlFedAuthInfo {
  418. internal string spn;
  419. internal string stsurl;
  420. public override string ToString() {
  421. return String.Format(CultureInfo.InvariantCulture, "STSURL: {0}, SPN: {1}", stsurl ?? String.Empty, spn ?? String.Empty);
  422. }
  423. }
  424. sealed internal class SqlFedAuthToken {
  425. internal UInt32 dataLen;
  426. internal byte[] accessToken;
  427. internal long expirationFileTime;
  428. }
  429. sealed internal class _SqlMetaData : SqlMetaDataPriv, ICloneable {
  430. internal string column;
  431. internal string baseColumn;
  432. internal MultiPartTableName multiPartTableName;
  433. internal readonly int ordinal;
  434. internal byte updatability; // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown)
  435. internal byte tableNum;
  436. internal bool isDifferentName;
  437. internal bool isKey;
  438. internal bool isHidden;
  439. internal bool isExpression;
  440. internal bool isIdentity;
  441. internal bool isColumnSet;
  442. internal byte op; // for altrow-columns only
  443. internal ushort operand; // for altrow-columns only
  444. internal _SqlMetaData(int ordinal) : base() {
  445. this.ordinal = ordinal;
  446. }
  447. internal string serverName {
  448. get {
  449. return multiPartTableName.ServerName;
  450. }
  451. }
  452. internal string catalogName {
  453. get {
  454. return multiPartTableName.CatalogName;
  455. }
  456. }
  457. internal string schemaName {
  458. get {
  459. return multiPartTableName.SchemaName;
  460. }
  461. }
  462. internal string tableName {
  463. get {
  464. return multiPartTableName.TableName;
  465. }
  466. }
  467. internal bool IsNewKatmaiDateTimeType {
  468. get {
  469. return SqlDbType.Date == type || SqlDbType.Time == type || SqlDbType.DateTime2 == type || SqlDbType.DateTimeOffset == type;
  470. }
  471. }
  472. internal bool IsLargeUdt {
  473. get {
  474. return type == SqlDbType.Udt && length == Int32.MaxValue;
  475. }
  476. }
  477. public object Clone() {
  478. _SqlMetaData result = new _SqlMetaData(ordinal);
  479. result.CopyFrom(this);
  480. result.column = column;
  481. result.baseColumn = baseColumn;
  482. result.multiPartTableName = multiPartTableName;
  483. result.updatability = updatability;
  484. result.tableNum = tableNum;
  485. result.isDifferentName = isDifferentName;
  486. result.isKey = isKey;
  487. result.isHidden = isHidden;
  488. result.isExpression = isExpression;
  489. result.isIdentity = isIdentity;
  490. result.isColumnSet = isColumnSet;
  491. result.op = op;
  492. result.operand = operand;
  493. return result;
  494. }
  495. }
  496. sealed internal class _SqlMetaDataSet : ICloneable {
  497. internal ushort id; // for altrow-columns only
  498. internal int[] indexMap;
  499. internal int visibleColumns;
  500. internal DataTable schemaTable;
  501. internal readonly SqlTceCipherInfoTable? cekTable; // table of "column encryption keys" used for this metadataset
  502. internal readonly _SqlMetaData[] metaDataArray;
  503. internal _SqlMetaDataSet(int count, SqlTceCipherInfoTable? cipherTable) {
  504. cekTable = cipherTable;
  505. metaDataArray = new _SqlMetaData[count];
  506. for(int i = 0; i < metaDataArray.Length; ++i) {
  507. metaDataArray[i] = new _SqlMetaData(i);
  508. }
  509. }
  510. private _SqlMetaDataSet(_SqlMetaDataSet original) {
  511. this.id = original.id;
  512. // although indexMap is not immutable, in practice it is initialized once and then passed around
  513. this.indexMap = original.indexMap;
  514. this.visibleColumns = original.visibleColumns;
  515. this.schemaTable = original.schemaTable;
  516. if (original.metaDataArray == null) {
  517. metaDataArray = null;
  518. }
  519. else {
  520. metaDataArray = new _SqlMetaData[original.metaDataArray.Length];
  521. for (int idx=0; idx<metaDataArray.Length; idx++) {
  522. metaDataArray[idx] = (_SqlMetaData)original.metaDataArray[idx].Clone();
  523. }
  524. }
  525. }
  526. internal int Length {
  527. get {
  528. return metaDataArray.Length;
  529. }
  530. }
  531. internal _SqlMetaData this [int index] {
  532. get {
  533. return metaDataArray[index];
  534. }
  535. set {
  536. Debug.Assert(null == value, "used only by SqlBulkCopy");
  537. metaDataArray[index] = value;
  538. }
  539. }
  540. public object Clone() {
  541. return new _SqlMetaDataSet(this);
  542. }
  543. }
  544. sealed internal class _SqlMetaDataSetCollection : ICloneable {
  545. private readonly List<_SqlMetaDataSet> altMetaDataSetArray;
  546. internal _SqlMetaDataSet metaDataSet;
  547. internal _SqlMetaDataSetCollection () {
  548. altMetaDataSetArray = new List<_SqlMetaDataSet>();
  549. }
  550. internal void SetAltMetaData(_SqlMetaDataSet altMetaDataSet) {
  551. // VSTFDEVDIV 479675: if altmetadata with same id is found, override it rather than adding a new one
  552. int newId = altMetaDataSet.id;
  553. for (int i = 0; i < altMetaDataSetArray.Count; i++) {
  554. if (altMetaDataSetArray[i].id == newId) {
  555. // override the existing metadata with the same id
  556. altMetaDataSetArray[i] = altMetaDataSet;
  557. return;
  558. }
  559. }
  560. // if we did not find metadata to override, add as new
  561. altMetaDataSetArray.Add(altMetaDataSet);
  562. }
  563. internal _SqlMetaDataSet GetAltMetaData(int id) {
  564. foreach (_SqlMetaDataSet altMetaDataSet in altMetaDataSetArray) {
  565. if (altMetaDataSet.id == id) {
  566. return altMetaDataSet;
  567. }
  568. }
  569. Debug.Assert (false, "Can't match up altMetaDataSet with given id");
  570. return null;
  571. }
  572. public object Clone()
  573. {
  574. _SqlMetaDataSetCollection result = new _SqlMetaDataSetCollection();
  575. result.metaDataSet = metaDataSet == null ? null : (_SqlMetaDataSet)metaDataSet.Clone();
  576. foreach (_SqlMetaDataSet set in altMetaDataSetArray) {
  577. result.altMetaDataSetArray.Add((_SqlMetaDataSet)set.Clone());
  578. }
  579. return result;
  580. }
  581. }
  582. /// <summary>
  583. /// Represents Encryption related information of the cipher data.
  584. /// </summary>
  585. internal class SqlCipherMetadata {
  586. /// <summary>
  587. /// Cipher Info Entry.
  588. /// </summary>
  589. private SqlTceCipherInfoEntry? _sqlTceCipherInfoEntry;
  590. /// <summary>
  591. /// Encryption Algorithm Id.
  592. /// </summary>
  593. private readonly byte _cipherAlgorithmId;
  594. /// <summary>
  595. /// Encryption Algorithm Name.
  596. /// </summary>
  597. private readonly string _cipherAlgorithmName;
  598. /// <summary>
  599. /// Encryption Type.
  600. /// </summary>
  601. private readonly byte _encryptionType;
  602. /// <summary>
  603. /// Normalization Rule Version.
  604. /// </summary>
  605. private readonly byte _normalizationRuleVersion;
  606. /// <summary>
  607. /// Encryption Algorithm Handle.
  608. /// </summary>
  609. private SqlClientEncryptionAlgorithm _sqlClientEncryptionAlgorithm;
  610. /// <summary>
  611. /// Sql Encryption Key Info.
  612. /// </summary>
  613. private SqlEncryptionKeyInfo? _sqlEncryptionKeyInfo;
  614. /// <summary>
  615. /// Ordinal (into the Cek Table).
  616. /// </summary>
  617. private readonly ushort _ordinal;
  618. /// <summary>
  619. /// Return the Encryption Info Entry.
  620. /// </summary>
  621. internal SqlTceCipherInfoEntry? EncryptionInfo {
  622. get {
  623. return _sqlTceCipherInfoEntry;
  624. }
  625. set {
  626. Debug.Assert(!_sqlTceCipherInfoEntry.HasValue, "We can only set the EncryptionInfo once.");
  627. _sqlTceCipherInfoEntry = value;
  628. }
  629. }
  630. /// <summary>
  631. /// Return the cipher's encryption algorithm id.
  632. /// </summary>
  633. internal byte CipherAlgorithmId {
  634. get {
  635. return _cipherAlgorithmId;
  636. }
  637. }
  638. /// <summary>
  639. /// Return the cipher's encryption algorithm name (could be null).
  640. /// </summary>
  641. internal string CipherAlgorithmName {
  642. get {
  643. return _cipherAlgorithmName;
  644. }
  645. }
  646. /// <summary>
  647. /// Return EncryptionType (Deterministic, Randomized, etc.)
  648. /// </summary>
  649. internal byte EncryptionType {
  650. get {
  651. return _encryptionType;
  652. }
  653. }
  654. /// <summary>
  655. /// Return normalization rule version.
  656. /// </summary>
  657. internal byte NormalizationRuleVersion {
  658. get {
  659. return _normalizationRuleVersion;
  660. }
  661. }
  662. /// <summary>
  663. /// Return the cipher encyrption algorithm handle.
  664. /// </summary>
  665. internal SqlClientEncryptionAlgorithm CipherAlgorithm {
  666. get {
  667. return _sqlClientEncryptionAlgorithm;
  668. }
  669. set {
  670. Debug.Assert(_sqlClientEncryptionAlgorithm == null, "_sqlClientEncryptionAlgorithm should not be set more than once.");
  671. _sqlClientEncryptionAlgorithm = value;
  672. }
  673. }
  674. /// <summary>
  675. /// Return Encryption Key Info.
  676. /// </summary>
  677. internal SqlEncryptionKeyInfo? EncryptionKeyInfo {
  678. get {
  679. return _sqlEncryptionKeyInfo;
  680. }
  681. set {
  682. Debug.Assert(!_sqlEncryptionKeyInfo.HasValue, "_sqlEncryptionKeyInfo should not be set more than once.");
  683. _sqlEncryptionKeyInfo = value;
  684. }
  685. }
  686. /// <summary>
  687. /// Return Ordinal into Cek Table.
  688. /// </summary>
  689. internal ushort CekTableOrdinal {
  690. get {
  691. return _ordinal;
  692. }
  693. }
  694. /// <summary>
  695. /// Constructor.
  696. /// </summary>
  697. /// <param name="sqlTceCipherInfoEntry"></param>
  698. /// <param name="sqlClientEncryptionAlgorithm"></param>
  699. /// <param name="cipherAlgorithmId"></param>
  700. /// <param name="encryptionType"></param>
  701. /// <param name="normalizationRuleVersion"></param>
  702. internal SqlCipherMetadata (SqlTceCipherInfoEntry? sqlTceCipherInfoEntry,
  703. ushort ordinal,
  704. byte cipherAlgorithmId,
  705. string cipherAlgorithmName,
  706. byte encryptionType,
  707. byte normalizationRuleVersion) {
  708. Debug.Assert(!sqlTceCipherInfoEntry.Equals(default(SqlTceCipherInfoEntry)), "sqlTceCipherInfoEntry should not be un-initialized.");
  709. _sqlTceCipherInfoEntry = sqlTceCipherInfoEntry;
  710. _ordinal = ordinal;
  711. _cipherAlgorithmId = cipherAlgorithmId;
  712. _cipherAlgorithmName = cipherAlgorithmName;
  713. _encryptionType = encryptionType;
  714. _normalizationRuleVersion = normalizationRuleVersion;
  715. _sqlEncryptionKeyInfo = null;
  716. }
  717. /// <summary>
  718. /// Do we have an handle to the cipher encryption algorithm already ?
  719. /// </summary>
  720. /// <returns></returns>
  721. internal bool IsAlgorithmInitialized() {
  722. return (null != _sqlClientEncryptionAlgorithm) ? true : false;
  723. }
  724. }
  725. internal class SqlMetaDataPriv {
  726. internal SqlDbType type; // SqlDbType enum value
  727. internal byte tdsType; // underlying tds type
  728. internal byte precision = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
  729. internal byte scale = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1)
  730. internal int length;
  731. internal SqlCollation collation;
  732. internal int codePage;
  733. internal Encoding encoding;
  734. internal bool isNullable;
  735. internal bool isMultiValued = false;
  736. // UDT specific metadata
  737. // server metadata info
  738. // additional temporary UDT meta data
  739. internal string udtDatabaseName;
  740. internal string udtSchemaName;
  741. internal string udtTypeName;
  742. internal string udtAssemblyQualifiedName;
  743. // on demand
  744. internal Type udtType;
  745. // Xml specific metadata
  746. internal string xmlSchemaCollectionDatabase;
  747. internal string xmlSchemaCollectionOwningSchema;
  748. internal string xmlSchemaCollectionName;
  749. internal MetaType metaType; // cached metaType
  750. // Structured type-specific metadata
  751. internal string structuredTypeDatabaseName;
  752. internal string structuredTypeSchemaName;
  753. internal string structuredTypeName;
  754. internal IList<SmiMetaData> structuredFields;
  755. internal bool isEncrypted; // TCE encrypted?
  756. internal SqlMetaDataPriv baseTI; // for encrypted columns, represents the TYPE_INFO for plaintext value
  757. internal SqlCipherMetadata cipherMD; // Cipher related metadata for encrypted columns.
  758. internal SqlMetaDataPriv() {
  759. }
  760. internal virtual void CopyFrom(SqlMetaDataPriv original) {
  761. this.type = original.type;
  762. this.tdsType = original.tdsType;
  763. this.precision = original.precision;
  764. this.scale = original.scale;
  765. this.length = original.length;
  766. this.collation = original.collation;
  767. this.codePage = original.codePage;
  768. this.encoding = original.encoding;
  769. this.isNullable = original.isNullable;
  770. this.isMultiValued = original.isMultiValued;
  771. this.udtDatabaseName = original.udtDatabaseName;
  772. this.udtSchemaName = original.udtSchemaName;
  773. this.udtTypeName = original.udtTypeName;
  774. this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName;
  775. this.udtType = original.udtType;
  776. this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase;
  777. this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema;
  778. this.xmlSchemaCollectionName = original.xmlSchemaCollectionName;
  779. this.metaType = original.metaType;
  780. //
  781. this.structuredTypeDatabaseName = original.structuredTypeDatabaseName;
  782. this.structuredTypeSchemaName = original.structuredTypeSchemaName;
  783. this.structuredTypeName = original.structuredTypeName;
  784. this.structuredFields = original.structuredFields;
  785. }
  786. /// <summary>
  787. /// Is the algorithm handle for the cipher encryption initialized ?
  788. /// </summary>
  789. /// <returns></returns>
  790. internal bool IsAlgorithmInitialized() {
  791. if (null != cipherMD) {
  792. return cipherMD.IsAlgorithmInitialized();
  793. }
  794. return false;
  795. }
  796. /// <summary>
  797. /// Returns the normalization rule version byte.
  798. /// </summary>
  799. /// <returns></returns>
  800. internal byte NormalizationRuleVersion {
  801. get {
  802. if (null != cipherMD){
  803. return cipherMD.NormalizationRuleVersion;
  804. }
  805. return 0x00;
  806. }
  807. }
  808. }
  809. /// <summary>
  810. /// Class encapsulating additional information when sending encrypted input parameters.
  811. /// </summary>
  812. sealed internal class SqlColumnEncryptionInputParameterInfo
  813. {
  814. /// <summary>
  815. /// Metadata of the parameter to write the TYPE_INFO of the unencrypted column data type.
  816. /// </summary>
  817. private readonly SmiParameterMetaData _smiParameterMetadata;
  818. /// <summary>
  819. /// Column encryption related metadata.
  820. /// </summary>
  821. private readonly SqlCipherMetadata _cipherMetadata;
  822. /// <summary>
  823. /// Serialized format for a subset of members.
  824. /// Does not include _smiParameterMetadata's serialization.
  825. /// </summary>
  826. private readonly byte[] _serializedWireFormat;
  827. /// <summary>
  828. /// Return the SMI Parameter Metadata.
  829. /// </summary>
  830. internal SmiParameterMetaData ParameterMetadata {
  831. get {
  832. return _smiParameterMetadata;
  833. }
  834. }
  835. /// <summary>
  836. /// Return the serialized format for some members.
  837. /// This is pre-calculated and cached since members are immutable.
  838. /// Does not include _smiParameterMetadata's serialization.
  839. /// </summary>
  840. internal byte[] SerializedWireFormat
  841. {
  842. get {
  843. return _serializedWireFormat;
  844. }
  845. }
  846. /// <summary>
  847. /// Constructor.
  848. /// </summary>
  849. /// <param name="smiParameterMetadata"></param>
  850. /// <param name="cipherMetadata"></param>
  851. internal SqlColumnEncryptionInputParameterInfo(SmiParameterMetaData smiParameterMetadata, SqlCipherMetadata cipherMetadata) {
  852. Debug.Assert(smiParameterMetadata != null, "smiParameterMetadata should not be null.");
  853. Debug.Assert(cipherMetadata != null, "cipherMetadata should not be null");
  854. Debug.Assert(cipherMetadata.EncryptionKeyInfo.HasValue, "cipherMetadata.EncryptionKeyInfo.HasValue should be true.");
  855. _smiParameterMetadata = smiParameterMetadata;
  856. _cipherMetadata = cipherMetadata;
  857. _serializedWireFormat = SerializeToWriteFormat();
  858. }
  859. /// <summary>
  860. /// Serializes some data members to wire format.
  861. /// </summary>
  862. private byte[] SerializeToWriteFormat() {
  863. int totalLength = 0;
  864. // CipherAlgorithmId.
  865. totalLength += sizeof(byte);
  866. // Encryption Type.
  867. totalLength += sizeof(byte);
  868. // Database id of the encryption key.
  869. totalLength += sizeof(int);
  870. // Id of the encryption key.
  871. totalLength += sizeof(int);
  872. // Version of the encryption key.
  873. totalLength += sizeof(int);
  874. // Metadata version of the encryption key.
  875. totalLength += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
  876. // Normalization Rule Version.
  877. totalLength += sizeof(byte);
  878. byte[] serializedWireFormat = new byte[totalLength];
  879. // No:of bytes consumed till now. Running variable.
  880. int consumedBytes = 0;
  881. // 1 - Write Cipher Algorithm Id.
  882. serializedWireFormat[consumedBytes++] = _cipherMetadata.CipherAlgorithmId;
  883. // 2 - Write Encryption Type.
  884. serializedWireFormat[consumedBytes++] = _cipherMetadata.EncryptionType;
  885. // 3 - Write the database id of the encryption key.
  886. SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.databaseId, serializedWireFormat, ref consumedBytes);
  887. // 4 - Write the id of the encryption key.
  888. SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekId, serializedWireFormat, ref consumedBytes);
  889. // 5 - Write the version of the encryption key.
  890. SerializeIntIntoBuffer(_cipherMetadata.EncryptionKeyInfo.Value.cekVersion, serializedWireFormat, ref consumedBytes);
  891. // 6 - Write the metadata version of the encryption key.
  892. Buffer.BlockCopy(_cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion, 0, serializedWireFormat, consumedBytes, _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length);
  893. consumedBytes += _cipherMetadata.EncryptionKeyInfo.Value.cekMdVersion.Length;
  894. // 7 - Write Normalization Rule Version.
  895. serializedWireFormat[consumedBytes++] = _cipherMetadata.NormalizationRuleVersion;
  896. return serializedWireFormat;
  897. }
  898. /// <summary>
  899. /// Serializes an int into the provided buffer and offset.
  900. /// </summary>
  901. private void SerializeIntIntoBuffer(int value, byte[] buffer, ref int offset) {
  902. buffer[offset++] = (byte)(value & 0xff);
  903. buffer[offset++] = (byte)((value >> 8) & 0xff);
  904. buffer[offset++] = (byte)((value >> 16) & 0xff);
  905. buffer[offset++] = (byte)((value >> 24) & 0xff);
  906. }
  907. }
  908. sealed internal class _SqlRPC {
  909. internal string rpcName;
  910. internal string databaseName; // Used for UDTs
  911. internal ushort ProcID; // Used instead of name
  912. internal ushort options;
  913. internal SqlParameter[] parameters;
  914. internal byte[] paramoptions;
  915. internal int? recordsAffected;
  916. internal int cumulativeRecordsAffected;
  917. internal int errorsIndexStart;
  918. internal int errorsIndexEnd;
  919. internal SqlErrorCollection errors;
  920. internal int warningsIndexStart;
  921. internal int warningsIndexEnd;
  922. internal SqlErrorCollection warnings;
  923. internal bool needsFetchParameterEncryptionMetadata;
  924. internal string GetCommandTextOrRpcName() {
  925. if (TdsEnums.RPC_PROCID_EXECUTESQL == ProcID) {
  926. // Param 0 is the actual sql executing
  927. return (string)parameters[0].Value;
  928. }
  929. else {
  930. return rpcName;
  931. }
  932. }
  933. }
  934. sealed internal class SqlReturnValue : SqlMetaDataPriv {
  935. internal ushort parmIndex; //Yukon or later only
  936. internal string parameter;
  937. internal readonly SqlBuffer value;
  938. internal SqlReturnValue() : base() {
  939. value = new SqlBuffer();
  940. }
  941. }
  942. internal struct MultiPartTableName {
  943. private string _multipartName;
  944. private string _serverName;
  945. private string _catalogName;
  946. private string _schemaName;
  947. private string _tableName;
  948. internal MultiPartTableName(string[] parts) {
  949. _multipartName = null;
  950. _serverName = parts[0];
  951. _catalogName = parts[1];
  952. _schemaName = parts[2];
  953. _tableName = parts[3];
  954. }
  955. internal MultiPartTableName(string multipartName) {
  956. _multipartName = multipartName;
  957. _serverName = null;
  958. _catalogName = null;
  959. _schemaName = null;
  960. _tableName = null;
  961. }
  962. internal string ServerName {
  963. get {
  964. ParseMultipartName();
  965. return _serverName;
  966. }
  967. set { _serverName = value; }
  968. }
  969. internal string CatalogName {
  970. get {
  971. ParseMultipartName();
  972. return _catalogName;
  973. }
  974. set { _catalogName = value; }
  975. }
  976. internal string SchemaName {
  977. get {
  978. ParseMultipartName();
  979. return _schemaName;
  980. }
  981. set { _schemaName = value; }
  982. }
  983. internal string TableName {
  984. get {
  985. ParseMultipartName();
  986. return _tableName;
  987. }
  988. set { _tableName = value; }
  989. }
  990. private void ParseMultipartName() {
  991. if (null != _multipartName) {
  992. string[] parts = MultipartIdentifier.ParseMultipartIdentifier(_multipartName, "[\"", "]\"", Res.SQL_TDSParserTableName, false);
  993. _serverName = parts[0];
  994. _catalogName = parts[1];
  995. _schemaName = parts[2];
  996. _tableName = parts[3];
  997. _multipartName = null;
  998. }
  999. }
  1000. internal static readonly MultiPartTableName Null = new MultiPartTableName(new string[] {null, null, null, null});
  1001. }
  1002. }