1 //------------------------------------------------------------------------------
2 // <copyright file="NameValuePermission.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.Common {
11 using System.Collections;
12 using System.Data.Common;
13 using System.Diagnostics;
14 using System.Globalization;
15 using System.Security;
16 using System.Security.Permissions;
19 [Serializable] // MDAC 83147
20 sealed internal class NameValuePermission : IComparable {
21 // reused as both key and value nodes
22 // key nodes link to value nodes
23 // value nodes link to key nodes
24 private string _value;
26 // value node with (null != _restrictions) are allowed to match connection strings
27 private DBConnectionString _entry;
29 private NameValuePermission[] _tree; // with branches
31 static internal readonly NameValuePermission Default = null;// = new NameValuePermission(String.Empty, new string[] { "File Name" }, KeyRestrictionBehavior.AllowOnly);
33 internal NameValuePermission() { // root node
36 private NameValuePermission(string keyword) {
40 private NameValuePermission(string value, DBConnectionString entry) {
45 private NameValuePermission(NameValuePermission permit) { // deep-copy
46 _value = permit._value;
47 _entry = permit._entry;
50 NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]);
51 for(int i = 0; i < tree.Length; ++i) {
52 if (null != tree[i]) { // WebData 98488
53 tree[i] = tree[i].CopyNameValue(); // deep copy
60 int IComparable.CompareTo(object a) {
61 return StringComparer.Ordinal.Compare(_value, ((NameValuePermission)a)._value);
64 static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) {
65 Debug.Assert(null != entry, "null DBConnectionString");
67 if (null != entry.KeyChain) {
68 for(NameValuePair keychain = entry.KeyChain; null != keychain; keychain = keychain.Next) {
69 NameValuePermission kv;
71 kv = kvtree.CheckKeyForValue(keychain.Name);
73 kv = new NameValuePermission(keychain.Name);
74 kvtree.Add(kv); // add directly into live tree
78 kv = kvtree.CheckKeyForValue(keychain.Value);
80 DBConnectionString insertValue = ((null != keychain.Next) ? null : entry);
81 kv = new NameValuePermission(keychain.Value, insertValue);
82 kvtree.Add(kv); // add directly into live tree
83 if (null != insertValue) {
84 entries.Add(insertValue);
87 else if (null == keychain.Next) { // shorter chain potential
88 if (null != kv._entry) {
89 Debug.Assert(entries.Contains(kv._entry), "entries doesn't contain entry");
90 entries.Remove(kv._entry);
91 kv._entry = kv._entry.Intersect(entry); // union new restrictions into existing tree
96 entries.Add(kv._entry);
101 else { // global restrictions, MDAC 84443
102 DBConnectionString kentry = kvtree._entry;
103 if (null != kentry) {
104 Debug.Assert(entries.Contains(kentry), "entries doesn't contain entry");
105 entries.Remove(kentry);
106 kvtree._entry = kentry.Intersect(entry);
109 kvtree._entry = entry;
111 entries.Add(kvtree._entry);
115 internal void Intersect(ArrayList entries, NameValuePermission target) {
116 if (null == target) {
121 if (null != _entry) {
122 entries.Remove(_entry);
123 _entry = _entry.Intersect(target._entry);
126 else if (null != target._entry) {
127 _entry = target._entry.Intersect(null);
132 int count = _tree.Length;
133 for(int i = 0; i < _tree.Length; ++i) {
134 NameValuePermission kvtree = target.CheckKeyForValue(_tree[i]._value);
135 if (null != kvtree) { // does target tree contain our value
136 _tree[i].Intersect(entries, kvtree);
146 else if (count < _tree.Length) {
147 NameValuePermission[] kvtree = new NameValuePermission[count];
148 for (int i = 0, j = 0; i < _tree.Length; ++i) {
149 if(null != _tree[i]) {
150 kvtree[j++] = _tree[i];
159 private void Add(NameValuePermission permit) {
160 NameValuePermission[] tree = _tree;
161 int length = ((null != tree) ? tree.Length : 0);
162 NameValuePermission[] newtree = new NameValuePermission[1+length];
163 for(int i = 0; i < newtree.Length-1; ++i) {
164 newtree[i] = tree[i];
166 newtree[length] = permit;
171 internal bool CheckValueForKeyPermit(DBConnectionString parsetable) {
172 if (null == parsetable) {
175 bool hasMatch = false;
176 NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it
177 if (null != keytree) {
178 hasMatch = parsetable.IsEmpty; // MDAC 86773
181 // which key do we follow the key-value chain on
182 for (int i = 0; i < keytree.Length; ++i) {
183 NameValuePermission permitKey = keytree[i];
184 if (null != permitKey) {
185 string keyword = permitKey._value;
187 Debug.Assert(null == permitKey._entry, "key member has no restrictions");
189 if (parsetable.ContainsKey(keyword)) {
190 string valueInQuestion = (string)parsetable[keyword];
192 // keyword is restricted to certain values
193 NameValuePermission permitValue = permitKey.CheckKeyForValue(valueInQuestion);
194 if (null != permitValue) {
195 //value does match - continue the chain down that branch
196 if (permitValue.CheckValueForKeyPermit(parsetable)) {
198 // adding a break statement 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("data provider=msdatashape;provider=sqloledb;integrated security=sspi", "", KeyRestrictionBehavior.AllowOnly);
203 else { // failed branch checking
207 else { // value doesn't match to expected values - fail here
212 // else try next keyword
215 // partial chain match, either leaf-node by shorter chain or fail mid-chain if (null == _restrictions)
218 DBConnectionString entry = _entry;
220 // also checking !hasMatch is tempting, but wrong
221 // user can safetly extend their restrictions for current rule to include missing keyword
222 // i.e. Add("provider=sqloledb;integrated security=sspi", "data provider=", KeyRestrictionBehavior.AllowOnly);
223 // i.e. Add("provider=sqloledb;", "integrated security=;", KeyRestrictionBehavior.AllowOnly);
224 hasMatch = entry.IsSupersetOf(parsetable);
227 return hasMatch; // mid-chain failure
230 private NameValuePermission CheckKeyForValue(string keyInQuestion) {
231 NameValuePermission[] valuetree = _tree; // _tree won't mutate but Add will replace it
232 if (null != valuetree) {
233 for (int i = 0; i < valuetree.Length; ++i) {
234 NameValuePermission permitValue = valuetree[i];
235 if (String.Equals(keyInQuestion, permitValue._value, StringComparison.OrdinalIgnoreCase)) {
243 internal NameValuePermission CopyNameValue() {
244 return new NameValuePermission(this);