2
0

NameValuePermission.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //------------------------------------------------------------------------------
  2. // <copyright file="NameValuePermission.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.Common {
  9. using System.Collections;
  10. using System.Data.Common;
  11. using System.Diagnostics;
  12. using System.Globalization;
  13. using System.Security;
  14. using System.Security.Permissions;
  15. using System.Text;
  16. [Serializable] // MDAC 83147
  17. sealed internal class NameValuePermission : IComparable {
  18. // reused as both key and value nodes
  19. // key nodes link to value nodes
  20. // value nodes link to key nodes
  21. private string _value;
  22. // value node with (null != _restrictions) are allowed to match connection strings
  23. private DBConnectionString _entry;
  24. private NameValuePermission[] _tree; // with branches
  25. static internal readonly NameValuePermission Default = null;// = new NameValuePermission(String.Empty, new string[] { "File Name" }, KeyRestrictionBehavior.AllowOnly);
  26. internal NameValuePermission() { // root node
  27. }
  28. private NameValuePermission(string keyword) {
  29. _value = keyword;
  30. }
  31. private NameValuePermission(string value, DBConnectionString entry) {
  32. _value = value;
  33. _entry = entry;
  34. }
  35. private NameValuePermission(NameValuePermission permit) { // deep-copy
  36. _value = permit._value;
  37. _entry = permit._entry;
  38. _tree = permit._tree;
  39. if (null != _tree) {
  40. NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]);
  41. for(int i = 0; i < tree.Length; ++i) {
  42. if (null != tree[i]) { // WebData 98488
  43. tree[i] = tree[i].CopyNameValue(); // deep copy
  44. }
  45. }
  46. _tree = tree;
  47. }
  48. }
  49. int IComparable.CompareTo(object a) {
  50. return StringComparer.Ordinal.Compare(_value, ((NameValuePermission)a)._value);
  51. }
  52. static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) {
  53. Debug.Assert(null != entry, "null DBConnectionString");
  54. if (null != entry.KeyChain) {
  55. for(NameValuePair keychain = entry.KeyChain; null != keychain; keychain = keychain.Next) {
  56. NameValuePermission kv;
  57. kv = kvtree.CheckKeyForValue(keychain.Name);
  58. if (null == kv) {
  59. kv = new NameValuePermission(keychain.Name);
  60. kvtree.Add(kv); // add directly into live tree
  61. }
  62. kvtree = kv;
  63. kv = kvtree.CheckKeyForValue(keychain.Value);
  64. if (null == kv) {
  65. DBConnectionString insertValue = ((null != keychain.Next) ? null : entry);
  66. kv = new NameValuePermission(keychain.Value, insertValue);
  67. kvtree.Add(kv); // add directly into live tree
  68. if (null != insertValue) {
  69. entries.Add(insertValue);
  70. }
  71. }
  72. else if (null == keychain.Next) { // shorter chain potential
  73. if (null != kv._entry) {
  74. Debug.Assert(entries.Contains(kv._entry), "entries doesn't contain entry");
  75. entries.Remove(kv._entry);
  76. kv._entry = kv._entry.Intersect(entry); // union new restrictions into existing tree
  77. }
  78. else {
  79. kv._entry = entry;
  80. }
  81. entries.Add(kv._entry);
  82. }
  83. kvtree = kv;
  84. }
  85. }
  86. else { // global restrictions, MDAC 84443
  87. DBConnectionString kentry = kvtree._entry;
  88. if (null != kentry) {
  89. Debug.Assert(entries.Contains(kentry), "entries doesn't contain entry");
  90. entries.Remove(kentry);
  91. kvtree._entry = kentry.Intersect(entry);
  92. }
  93. else {
  94. kvtree._entry = entry;
  95. }
  96. entries.Add(kvtree._entry);
  97. }
  98. }
  99. internal void Intersect(ArrayList entries, NameValuePermission target) {
  100. if (null == target) {
  101. _tree = null;
  102. _entry = null;
  103. }
  104. else {
  105. if (null != _entry) {
  106. entries.Remove(_entry);
  107. _entry = _entry.Intersect(target._entry);
  108. entries.Add(_entry);
  109. }
  110. else if (null != target._entry) {
  111. _entry = target._entry.Intersect(null);
  112. entries.Add(_entry);
  113. }
  114. if (null != _tree) {
  115. int count = _tree.Length;
  116. for(int i = 0; i < _tree.Length; ++i) {
  117. NameValuePermission kvtree = target.CheckKeyForValue(_tree[i]._value);
  118. if (null != kvtree) { // does target tree contain our value
  119. _tree[i].Intersect(entries, kvtree);
  120. }
  121. else {
  122. _tree[i] = null;
  123. --count;
  124. }
  125. }
  126. if (0 == count) {
  127. _tree = null;
  128. }
  129. else if (count < _tree.Length) {
  130. NameValuePermission[] kvtree = new NameValuePermission[count];
  131. for (int i = 0, j = 0; i < _tree.Length; ++i) {
  132. if(null != _tree[i]) {
  133. kvtree[j++] = _tree[i];
  134. }
  135. }
  136. _tree = kvtree;
  137. }
  138. }
  139. }
  140. }
  141. private void Add(NameValuePermission permit) {
  142. NameValuePermission[] tree = _tree;
  143. int length = ((null != tree) ? tree.Length : 0);
  144. NameValuePermission[] newtree = new NameValuePermission[1+length];
  145. for(int i = 0; i < newtree.Length-1; ++i) {
  146. newtree[i] = tree[i];
  147. }
  148. newtree[length] = permit;
  149. Array.Sort(newtree);
  150. _tree = newtree;
  151. }
  152. internal bool CheckValueForKeyPermit(DBConnectionString parsetable) {
  153. if (null == parsetable) {
  154. return false;
  155. }
  156. bool hasMatch = false;
  157. NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it
  158. if (null != keytree) {
  159. hasMatch = parsetable.IsEmpty; // MDAC 86773
  160. if (!hasMatch) {
  161. // which key do we follow the key-value chain on
  162. for (int i = 0; i < keytree.Length; ++i) {
  163. NameValuePermission permitKey = keytree[i];
  164. if (null != permitKey) {
  165. string keyword = permitKey._value;
  166. #if DEBUG
  167. Debug.Assert(null == permitKey._entry, "key member has no restrictions");
  168. #endif
  169. if (parsetable.ContainsKey(keyword)) {
  170. string valueInQuestion = (string)parsetable[keyword];
  171. // keyword is restricted to certain values
  172. NameValuePermission permitValue = permitKey.CheckKeyForValue(valueInQuestion);
  173. if (null != permitValue) {
  174. //value does match - continue the chain down that branch
  175. if (permitValue.CheckValueForKeyPermit(parsetable)) {
  176. hasMatch = true;
  177. // adding a break statement is tempting, but wrong
  178. // user can safetly extend their restrictions for current rule to include missing keyword
  179. // i.e. Add("provider=sqloledb;integrated security=sspi", "data provider=", KeyRestrictionBehavior.AllowOnly);
  180. // i.e. Add("data provider=msdatashape;provider=sqloledb;integrated security=sspi", "", KeyRestrictionBehavior.AllowOnly);
  181. }
  182. else { // failed branch checking
  183. return false;
  184. }
  185. }
  186. else { // value doesn't match to expected values - fail here
  187. return false;
  188. }
  189. }
  190. }
  191. // else try next keyword
  192. }
  193. }
  194. // partial chain match, either leaf-node by shorter chain or fail mid-chain if (null == _restrictions)
  195. }
  196. DBConnectionString entry = _entry;
  197. if (null != entry) {
  198. // also checking !hasMatch is tempting, but wrong
  199. // user can safetly extend their restrictions for current rule to include missing keyword
  200. // i.e. Add("provider=sqloledb;integrated security=sspi", "data provider=", KeyRestrictionBehavior.AllowOnly);
  201. // i.e. Add("provider=sqloledb;", "integrated security=;", KeyRestrictionBehavior.AllowOnly);
  202. hasMatch = entry.IsSupersetOf(parsetable);
  203. }
  204. return hasMatch; // mid-chain failure
  205. }
  206. private NameValuePermission CheckKeyForValue(string keyInQuestion) {
  207. NameValuePermission[] valuetree = _tree; // _tree won't mutate but Add will replace it
  208. if (null != valuetree) {
  209. for (int i = 0; i < valuetree.Length; ++i) {
  210. NameValuePermission permitValue = valuetree[i];
  211. if (String.Equals(keyInQuestion, permitValue._value, StringComparison.OrdinalIgnoreCase)) {
  212. return permitValue;
  213. }
  214. }
  215. }
  216. return null;
  217. }
  218. internal NameValuePermission CopyNameValue() {
  219. return new NameValuePermission(this);
  220. }
  221. }
  222. }