Welcome to mirror list, hosted at ThFree Co, Russian Federation.

NameValuePermission.cs « Common « Data « System « System.Data « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9f705d2568838f2cc0c2d20262e9fe4461bdf4e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//------------------------------------------------------------------------------
// <copyright file="NameValuePermission.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
// <owner current="true" primary="false">[....]</owner>
//------------------------------------------------------------------------------

namespace System.Data.Common {

    using System.Collections;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Globalization;
    using System.Security;
    using System.Security.Permissions;
    using System.Text;

    [Serializable] // MDAC 83147
    sealed internal class NameValuePermission : IComparable {
        // reused as both key and value nodes
        // key nodes link to value nodes
        // value nodes link to key nodes
        private string _value;

        // value node with (null != _restrictions) are allowed to match connection strings
        private DBConnectionString _entry;

        private NameValuePermission[] _tree; // with branches

        static internal readonly NameValuePermission Default = null;// = new NameValuePermission(String.Empty, new string[] { "File Name" }, KeyRestrictionBehavior.AllowOnly);

        internal NameValuePermission() { // root node
        }

        private NameValuePermission(string keyword) {
            _value = keyword;
       }

        private NameValuePermission(string value, DBConnectionString entry) {
            _value = value;
            _entry = entry;
        }

        private NameValuePermission(NameValuePermission permit) { // deep-copy
            _value = permit._value;
            _entry = permit._entry;
            _tree = permit._tree;
            if (null != _tree) {
                NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]);
                for(int i = 0; i < tree.Length; ++i) {
                    if (null != tree[i]) { // WebData 98488
                        tree[i] = tree[i].CopyNameValue(); // deep copy
                    }
                }
                _tree = tree;
            }
        }

        int IComparable.CompareTo(object a) {
            return StringComparer.Ordinal.Compare(_value, ((NameValuePermission)a)._value);
        }

        static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) {
            Debug.Assert(null != entry, "null DBConnectionString");

            if (null != entry.KeyChain) {
                for(NameValuePair keychain = entry.KeyChain; null != keychain; keychain = keychain.Next) {
                    NameValuePermission kv;

                    kv = kvtree.CheckKeyForValue(keychain.Name);
                    if (null == kv) {
                        kv = new NameValuePermission(keychain.Name);
                        kvtree.Add(kv); // add directly into live tree
                    }
                    kvtree = kv;

                    kv = kvtree.CheckKeyForValue(keychain.Value);
                    if (null == kv) {
                        DBConnectionString insertValue = ((null != keychain.Next) ? null : entry);
                        kv = new NameValuePermission(keychain.Value, insertValue);
                        kvtree.Add(kv); // add directly into live tree
                        if (null != insertValue) {
                            entries.Add(insertValue);
                        }
                    }
                    else if (null == keychain.Next) { // shorter chain potential
                        if (null != kv._entry) {
                            Debug.Assert(entries.Contains(kv._entry), "entries doesn't contain entry");
                            entries.Remove(kv._entry);
                            kv._entry = kv._entry.Intersect(entry); // union new restrictions into existing tree
                        }
                        else {
                            kv._entry = entry;
                        }
                        entries.Add(kv._entry);
                    }
                    kvtree = kv;
                }
            }
            else { // global restrictions, MDAC 84443
                DBConnectionString kentry = kvtree._entry;
                if (null != kentry) {
                    Debug.Assert(entries.Contains(kentry), "entries doesn't contain entry");
                    entries.Remove(kentry);
                    kvtree._entry = kentry.Intersect(entry);
                }
                else {
                    kvtree._entry = entry;
                }
                entries.Add(kvtree._entry);
            }
        }

        internal void Intersect(ArrayList entries, NameValuePermission target) {
            if (null == target) {
                _tree = null;
                _entry = null;
            }
            else {
                if (null != _entry) {
                    entries.Remove(_entry);
                    _entry = _entry.Intersect(target._entry);
                    entries.Add(_entry);
                }
                else if (null != target._entry) {
                    _entry = target._entry.Intersect(null);
                    entries.Add(_entry);
                }

                if (null != _tree) {
                    int count = _tree.Length;
                    for(int i = 0; i < _tree.Length; ++i) {
                        NameValuePermission kvtree = target.CheckKeyForValue(_tree[i]._value);
                        if (null != kvtree) { // does target tree contain our value
                            _tree[i].Intersect(entries, kvtree);
                        }
                        else {
                            _tree[i] = null;
                            --count;
                        }
                    }
                    if (0 == count) {
                        _tree = null;
                    }
                    else if (count < _tree.Length) {
                        NameValuePermission[] kvtree = new NameValuePermission[count];
                        for (int i = 0, j = 0; i < _tree.Length; ++i) {
                            if(null != _tree[i]) {
                                kvtree[j++] = _tree[i];
                            }
                        }
                        _tree = kvtree;
                    }
                }
            }
        }

        private void Add(NameValuePermission permit) {
            NameValuePermission[] tree = _tree;
            int length = ((null != tree) ? tree.Length : 0);
            NameValuePermission[] newtree = new NameValuePermission[1+length];
            for(int i = 0; i < newtree.Length-1; ++i) {
                newtree[i] = tree[i];
            }
            newtree[length] = permit;
            Array.Sort(newtree);
            _tree = newtree;
        }

        internal bool CheckValueForKeyPermit(DBConnectionString parsetable) {
            if (null == parsetable) {
                return false;
            }
            bool hasMatch = false;
            NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it
            if (null != keytree) {
                hasMatch = parsetable.IsEmpty; // MDAC 86773
                if (!hasMatch) {

                    // which key do we follow the key-value chain on
                    for (int i = 0; i < keytree.Length; ++i) {
                        NameValuePermission permitKey = keytree[i];
                        if (null != permitKey) {
                            string keyword = permitKey._value;
#if DEBUG
                            Debug.Assert(null == permitKey._entry, "key member has no restrictions");
#endif
                            if (parsetable.ContainsKey(keyword)) {
                                string valueInQuestion = (string)parsetable[keyword];

                                // keyword is restricted to certain values
                                NameValuePermission permitValue = permitKey.CheckKeyForValue(valueInQuestion);
                                if (null != permitValue) {
                                    //value does match - continue the chain down that branch
                                    if (permitValue.CheckValueForKeyPermit(parsetable)) {
                                        hasMatch = true;
                                        // adding a break statement is tempting, but wrong
                                        // user can safetly extend their restrictions for current rule to include missing keyword
                                        // i.e. Add("provider=sqloledb;integrated security=sspi", "data provider=", KeyRestrictionBehavior.AllowOnly);
                                        // i.e. Add("data provider=msdatashape;provider=sqloledb;integrated security=sspi", "", KeyRestrictionBehavior.AllowOnly);
                                    }
                                    else { // failed branch checking
                                        return false;
                                    }
                                }
                                else { // value doesn't match to expected values - fail here
                                    return false;
                                }
                            }
                        }
                        // else try next keyword
                    }
                }
                // partial chain match, either leaf-node by shorter chain or fail mid-chain if (null == _restrictions)
            }

            DBConnectionString entry = _entry;
            if (null != entry) {
                // also checking !hasMatch is tempting, but wrong
                // user can safetly extend their restrictions for current rule to include missing keyword
                // i.e. Add("provider=sqloledb;integrated security=sspi", "data provider=", KeyRestrictionBehavior.AllowOnly);
                // i.e. Add("provider=sqloledb;", "integrated security=;", KeyRestrictionBehavior.AllowOnly);
                hasMatch = entry.IsSupersetOf(parsetable);
            }

            return hasMatch; // mid-chain failure
        }

        private NameValuePermission CheckKeyForValue(string keyInQuestion) {
            NameValuePermission[] valuetree = _tree; // _tree won't mutate but Add will replace it
            if (null != valuetree) {
                for (int i = 0; i < valuetree.Length; ++i) {
                    NameValuePermission permitValue = valuetree[i];
                    if (String.Equals(keyInQuestion, permitValue._value, StringComparison.OrdinalIgnoreCase)) {
                        return permitValue;
                    }
                }
            }
            return null;
        }

        internal NameValuePermission CopyNameValue() {
            return new NameValuePermission(this);
        }
    }
}