From 249a9670b4c703ba3540219d912ec1584c83b2e5 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Apr 2025 11:56:44 -0500 Subject: [PATCH 1/7] Separate SqlClientPermissionAttribute class from SqlClientPermission.cs --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 ++ .../Data/SqlClient/SqlClientPermission.cs | 18 ----------- .../SqlClientPermissionAttribute.netfx.cs | 32 +++++++++++++++++++ 3 files changed, 35 insertions(+), 18 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermissionAttribute.netfx.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 20f02e7204..cfcdba4485 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -642,6 +642,9 @@ Microsoft\Data\SqlClient\SqlClientMetaDataCollectionNames.cs + + Microsoft\Data\SqlClient\SqlClientPermissionAttribute.netfx.cs + Microsoft\Data\SqlClient\SqlClientSymmetricKey.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs index 7672804655..66df4621e9 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs @@ -411,22 +411,4 @@ private static class XmlStr } - - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] - [Serializable] - public sealed class SqlClientPermissionAttribute : DBDataPermissionAttribute - { - - /// - public SqlClientPermissionAttribute(SecurityAction action) : base(action) - { - } - - /// - override public IPermission CreatePermission() - { - return new SqlClientPermission(this); - } - } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermissionAttribute.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermissionAttribute.netfx.cs new file mode 100644 index 0000000000..d26def255e --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermissionAttribute.netfx.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if NETFRAMEWORK + +using System; +using System.Data.Common; +using System.Security; +using System.Security.Permissions; + +namespace Microsoft.Data.SqlClient +{ + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] + [Serializable] + public sealed class SqlClientPermissionAttribute : DBDataPermissionAttribute + { + /// + public SqlClientPermissionAttribute(SecurityAction action) : base(action) + { + } + + /// + public override IPermission CreatePermission() + { + return new SqlClientPermission(this); + } + } +} + +#endif From b0909f3ef306ece697f55de55c84d094c723a2ca Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Apr 2025 12:08:01 -0500 Subject: [PATCH 2/7] Move SqlClientPermission to common project --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 +- .../SqlClient/SqlClientPermission.netfx.cs} | 39 ++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) rename src/Microsoft.Data.SqlClient/{netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs => src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs} (86%) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index cfcdba4485..702089f669 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -642,6 +642,9 @@ Microsoft\Data\SqlClient\SqlClientMetaDataCollectionNames.cs + + Microsoft\Data\SqlClient\SqlClientPermission.netfx.cs + Microsoft\Data\SqlClient\SqlClientPermissionAttribute.netfx.cs @@ -886,7 +889,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs similarity index 86% rename from src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index 66df4621e9..43f44ab4f8 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientPermission.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if NETFRAMEWORK + using System; using System.Collections; using System.Data; -using System.Data.Common; using System.Globalization; using System.Reflection; using System.Security; @@ -15,23 +16,23 @@ namespace Microsoft.Data.SqlClient { - /// + /// [Serializable] public sealed class SqlClientPermission : System.Data.Common.DBDataPermission { - /// + /// [Obsolete("SqlClientPermission() has been deprecated. Use the SqlClientPermission(PermissionState.None) constructor. http://go.microsoft.com/fwlink/?linkid=14202", true)] // MDAC 86034 public SqlClientPermission() : this(PermissionState.None) { } - /// + /// public SqlClientPermission(PermissionState state) : base(state) { } - /// + /// [Obsolete("SqlClientPermission(PermissionState state, Boolean allowBlankPassword) has been deprecated. Use the SqlClientPermission(PermissionState.None) constructor. http://go.microsoft.com/fwlink/?linkid=14202", true)] // MDAC 86034 public SqlClientPermission(PermissionState state, bool allowBlankPassword) : this(state) { @@ -61,15 +62,15 @@ internal SqlClientPermission(SqlConnectionString constr) : base(PermissionState. } } - /// + /// public override void Add(string connectionString, string restrictions, KeyRestrictionBehavior behavior) { DBConnectionString constr = new DBConnectionString(connectionString, restrictions, behavior, SqlConnectionString.GetParseSynonyms(), false); AddPermissionEntry(constr); } - /// - override public IPermission Copy() + /// + public override IPermission Copy() { return new SqlClientPermission(this); } @@ -126,8 +127,8 @@ private void CopyFrom(SqlClientPermission permission) } } - /// - override public IPermission Intersect(IPermission target) + /// + public override IPermission Intersect(IPermission target) { // used during Deny actions if (target == null) { @@ -179,8 +180,8 @@ private bool IsEmpty() return flag; } - /// - override public bool IsSubsetOf(IPermission target) + /// + public override bool IsSubsetOf(IPermission target) { if (null == target) { @@ -218,8 +219,8 @@ override public bool IsSubsetOf(IPermission target) return subset; } - /// - override public IPermission Union(IPermission target) + /// + public override IPermission Union(IPermission target) { if (target == null) { @@ -281,8 +282,8 @@ private string EncodeXmlValue(string value) // // // - /// - override public void FromXml(SecurityElement securityElement) + /// + public override void FromXml(SecurityElement securityElement) { // code derived from CodeAccessPermission.ValidateElement if (securityElement == null) @@ -344,8 +345,8 @@ override public void FromXml(SecurityElement securityElement) // // // - /// - override public SecurityElement ToXml() + /// + public override SecurityElement ToXml() { Type type = this.GetType(); SecurityElement root = new SecurityElement(XmlStr._IPermission); @@ -412,3 +413,5 @@ private static class XmlStr } } + +#endif From d2faeb7dd3ccc97842cc669b8777fc81fd07e9bf Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Apr 2025 12:25:26 -0500 Subject: [PATCH 3/7] Move NameValuePermission to be a subclass of SqlClientPermission (it's only used there) --- .../Data/Common/NameValuePermission.cs | 293 ------------------ .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 - .../SqlClient/SqlClientPermission.netfx.cs | 286 ++++++++++++++++- 3 files changed, 283 insertions(+), 297 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Common/Microsoft/Data/Common/NameValuePermission.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Common/Microsoft/Data/Common/NameValuePermission.cs b/src/Microsoft.Data.SqlClient/netfx/src/Common/Microsoft/Data/Common/NameValuePermission.cs deleted file mode 100644 index a7ad9be288..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Common/Microsoft/Data/Common/NameValuePermission.cs +++ /dev/null @@ -1,293 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Data.Common -{ - - using System; - using System.Collections; - using System.Diagnostics; - - [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 (_restrictions != null) 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 (_tree != null) - { - NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]); - for (int i = 0; i < tree.Length; ++i) - { - if (tree[i] != null) - { // 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(entry != null, "null DBConnectionString"); - - if (entry.KeyChain != null) - { - for (NameValuePair keychain = entry.KeyChain; keychain != null; keychain = keychain.Next) - { - NameValuePermission kv; - - kv = kvtree.CheckKeyForValue(keychain.Name); - if (kv == null) - { - kv = new NameValuePermission(keychain.Name); - kvtree.Add(kv); // add directly into live tree - } - kvtree = kv; - - kv = kvtree.CheckKeyForValue(keychain.Value); - if (kv == null) - { - DBConnectionString insertValue = keychain.Next != null ? null : entry; - kv = new NameValuePermission(keychain.Value, insertValue); - kvtree.Add(kv); // add directly into live tree - if (insertValue != null) - { - entries.Add(insertValue); - } - } - else if (keychain.Next == null) - { // shorter chain potential - if (kv._entry != null) - { - 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 (kentry != null) - { - 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 (target == null) - { - _tree = null; - _entry = null; - } - else - { - if (_entry != null) - { - entries.Remove(_entry); - _entry = _entry.Intersect(target._entry); - entries.Add(_entry); - } - else if (target._entry != null) - { - _entry = target._entry.Intersect(null); - entries.Add(_entry); - } - - if (_tree != null) - { - int count = _tree.Length; - for (int i = 0; i < _tree.Length; ++i) - { - NameValuePermission kvtree = target.CheckKeyForValue(_tree[i]._value); - if (kvtree != null) - { // 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 (_tree[i] != null) - { - kvtree[j++] = _tree[i]; - } - } - _tree = kvtree; - } - } - } - } - - private void Add(NameValuePermission permit) - { - NameValuePermission[] tree = _tree; - int length = tree != null ? 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 (parsetable == null) - { - return false; - } - bool hasMatch = false; - NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it - if (keytree != null) - { - 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 (permitKey != null) - { - string keyword = permitKey._value; -#if DEBUG - Debug.Assert(permitKey._entry == null, "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 (permitValue != null) - { - //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 safely 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 ( _restrictions == null) - } - - DBConnectionString entry = _entry; - if (entry != null) - { - // also checking !hasMatch is tempting, but wrong - // user can safely 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 (valuetree != null) - { - 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); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 702089f669..19d009424c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -873,7 +873,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index 43f44ab4f8..8e36132cda 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -7,6 +7,7 @@ using System; using System.Collections; using System.Data; +using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Security; @@ -20,7 +21,6 @@ namespace Microsoft.Data.SqlClient [Serializable] public sealed class SqlClientPermission : System.Data.Common.DBDataPermission { - /// [Obsolete("SqlClientPermission() has been deprecated. Use the SqlClientPermission(PermissionState.None) constructor. http://go.microsoft.com/fwlink/?linkid=14202", true)] // MDAC 86034 public SqlClientPermission() : this(PermissionState.None) @@ -392,6 +392,288 @@ public override SecurityElement ToXml() return root; } + private sealed 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 (_restrictions != null) 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 (_tree != null) + { + NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]); + for (int i = 0; i < tree.Length; ++i) + { + if (tree[i] != null) + { // 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(entry != null, "null DBConnectionString"); + + if (entry.KeyChain != null) + { + for (NameValuePair keychain = entry.KeyChain; keychain != null; keychain = keychain.Next) + { + NameValuePermission kv; + + kv = kvtree.CheckKeyForValue(keychain.Name); + if (kv == null) + { + kv = new NameValuePermission(keychain.Name); + kvtree.Add(kv); // add directly into live tree + } + kvtree = kv; + + kv = kvtree.CheckKeyForValue(keychain.Value); + if (kv == null) + { + DBConnectionString insertValue = keychain.Next != null ? null : entry; + kv = new NameValuePermission(keychain.Value, insertValue); + kvtree.Add(kv); // add directly into live tree + if (insertValue != null) + { + entries.Add(insertValue); + } + } + else if (keychain.Next == null) + { // shorter chain potential + if (kv._entry != null) + { + 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 (kentry != null) + { + 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 (target == null) + { + _tree = null; + _entry = null; + } + else + { + if (_entry != null) + { + entries.Remove(_entry); + _entry = _entry.Intersect(target._entry); + entries.Add(_entry); + } + else if (target._entry != null) + { + _entry = target._entry.Intersect(null); + entries.Add(_entry); + } + + if (_tree != null) + { + int count = _tree.Length; + for (int i = 0; i < _tree.Length; ++i) + { + NameValuePermission kvtree = target.CheckKeyForValue(_tree[i]._value); + if (kvtree != null) + { // 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 (_tree[i] != null) + { + kvtree[j++] = _tree[i]; + } + } + _tree = kvtree; + } + } + } + } + + private void Add(NameValuePermission permit) + { + NameValuePermission[] tree = _tree; + int length = tree != null ? 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 (parsetable == null) + { + return false; + } + bool hasMatch = false; + NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it + if (keytree != null) + { + 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 (permitKey != null) + { + string keyword = permitKey._value; + #if DEBUG + Debug.Assert(permitKey._entry == null, "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 (permitValue != null) + { + //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 safely 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 ( _restrictions == null) + } + + DBConnectionString entry = _entry; + if (entry != null) + { + // also checking !hasMatch is tempting, but wrong + // user can safely 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 (valuetree != null) + { + 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); + } + } + + private static class XmlStr { internal const string _class = "class"; @@ -409,8 +691,6 @@ private static class XmlStr internal const string _KeyRestrictions = "KeyRestrictions"; internal const string _KeyRestrictionBehavior = "KeyRestrictionBehavior"; } - - } } From b06a4c9a88034712373ca20056197d8be17375d0 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Apr 2025 12:50:32 -0500 Subject: [PATCH 4/7] Reorganize SqlClientPermision class --- .../SqlClient/SqlClientPermission.netfx.cs | 592 +++++++++--------- 1 file changed, 312 insertions(+), 280 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index 8e36132cda..2311e9ef16 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -19,8 +19,17 @@ namespace Microsoft.Data.SqlClient { /// [Serializable] - public sealed class SqlClientPermission : System.Data.Common.DBDataPermission + public sealed class SqlClientPermission : DBDataPermission { + #region Member Variables + + private NameValuePermission _keyvaluetree = NameValuePermission.Default; + private ArrayList _keyvalues;; + + #endregion + + #region Constructors + /// [Obsolete("SqlClientPermission() has been deprecated. Use the SqlClientPermission(PermissionState.None) constructor. http://go.microsoft.com/fwlink/?linkid=14202", true)] // MDAC 86034 public SqlClientPermission() : this(PermissionState.None) @@ -39,97 +48,138 @@ public SqlClientPermission(PermissionState state, bool allowBlankPassword) : thi AllowBlankPassword = allowBlankPassword; } - private SqlClientPermission(SqlClientPermission permission) : base(permission) - { // for Copy - // Explicitly copyFrom to clone the key value pairs - CopyFrom(permission); - } - internal SqlClientPermission(SqlClientPermissionAttribute permissionAttribute) : base(permissionAttribute) - { // for CreatePermission + { + // Used by SqlClientPermissionAttribute.CreatePermission } internal SqlClientPermission(SqlConnectionString constr) : base(PermissionState.None) - { // for Open + { + // Used by SqlConnectionString.CreatePermissionSet + if (constr != null) { AllowBlankPassword = constr.HasBlankPassword; // MDAC 84563 AddPermissionEntry(new DBConnectionString(constr)); } + if (constr == null || constr.IsEmpty) { base.Add("", "", KeyRestrictionBehavior.AllowOnly); } } + + private SqlClientPermission(SqlClientPermission permission) : base(permission) + { + // for Copy + // Explicitly copyFrom to clone the key value pairs + CopyFrom(permission); + } + + #endregion + + #region Properties + + private bool _IsUnrestricted + { + set + { + // Use Reflection to access the base class _isUnrestricted. There is no other way to alter this externally. + FieldInfo fieldInfo = GetType().BaseType.GetField("_isUnrestricted", BindingFlags.Instance + | BindingFlags.NonPublic); + fieldInfo.SetValue(this, value); + } + get + { + return base.IsUnrestricted(); + } + } + + #endregion + + #region Public/Internal Methods + /// public override void Add(string connectionString, string restrictions, KeyRestrictionBehavior behavior) { DBConnectionString constr = new DBConnectionString(connectionString, restrictions, behavior, SqlConnectionString.GetParseSynonyms(), false); AddPermissionEntry(constr); } - + /// public override IPermission Copy() { return new SqlClientPermission(this); } - - // Modifications - - private NameValuePermission _keyvaluetree = NameValuePermission.Default; - private /*DBConnectionString[]*/ArrayList _keyvalues; // = null; - - internal void AddPermissionEntry(DBConnectionString entry) + + // + // + // + /// + public override void FromXml(SecurityElement securityElement) { - if (_keyvaluetree == null) + // code derived from CodeAccessPermission.ValidateElement + if (securityElement == null) { - _keyvaluetree = new NameValuePermission(); + throw ADP.ArgumentNull("securityElement"); } - if (_keyvalues == null) + + string tag = securityElement.Tag; + if (!tag.Equals(XmlStr._Permission) && !tag.Equals(XmlStr._IPermission)) { - _keyvalues = new ArrayList(); + throw ADP.NotAPermissionElement(); } - NameValuePermission.AddEntry(_keyvaluetree, _keyvalues, entry); - _IsUnrestricted = false; // MDAC 84639 - } - - private bool _IsUnrestricted - { - set + + string version = securityElement.Attribute(XmlStr._Version); + if (version != null && !version.Equals(XmlStr._VersionNumber)) { - // Use Reflection to access the base class _isUnrestricted. There is no other way to alter this externally. - FieldInfo fieldInfo = GetType().BaseType.GetField("_isUnrestricted", BindingFlags.Instance - | BindingFlags.NonPublic); - fieldInfo.SetValue(this, value); + throw ADP.InvalidXMLBadVersion(); } - get - { - return base.IsUnrestricted(); - } - } + string unrestrictedValue = securityElement.Attribute(XmlStr._Unrestricted); + _IsUnrestricted = unrestrictedValue != null && bool.Parse(unrestrictedValue); - // Modified CopyFrom to make sure that we copy the Name Value Pair - private void CopyFrom(SqlClientPermission permission) - { + Clear(); // MDAC 83105 if (!_IsUnrestricted) { - if (permission._keyvalues != null) - { - _keyvalues = (ArrayList)permission._keyvalues.Clone(); + string allowNull = securityElement.Attribute(XmlStr._AllowBlankPassword); + AllowBlankPassword = allowNull != null && bool.Parse(allowNull); - if (permission._keyvaluetree != null) + ArrayList children = securityElement.Children; + if (children != null) + { + foreach (SecurityElement keyElement in children) { - _keyvaluetree = permission._keyvaluetree.CopyNameValue(); + tag = keyElement.Tag; + if (XmlStr._add == tag || (tag != null && XmlStr._add == tag.ToLower(CultureInfo.InvariantCulture))) + { + string constr = keyElement.Attribute(XmlStr._ConnectionString); + string restrt = keyElement.Attribute(XmlStr._KeyRestrictions); + string behavr = keyElement.Attribute(XmlStr._KeyRestrictionBehavior); + + KeyRestrictionBehavior behavior = KeyRestrictionBehavior.AllowOnly; + if (behavr != null) + { + behavior = (KeyRestrictionBehavior)Enum.Parse(typeof(KeyRestrictionBehavior), behavr, true); + } + constr = DecodeXmlValue(constr); + restrt = DecodeXmlValue(restrt); + Add(constr, restrt, behavior); + } } } } + else + { + AllowBlankPassword = false; + } } - + /// public override IPermission Intersect(IPermission target) - { // used during Deny actions + { + // used during Deny actions if (target == null) { return null; @@ -172,14 +222,7 @@ public override IPermission Intersect(IPermission target) } return newPermission; } - - private bool IsEmpty() - { // MDAC 84804 - ArrayList keyvalues = _keyvalues; - bool flag = !IsUnrestricted() && !AllowBlankPassword && (keyvalues == null || (0 == keyvalues.Count)); - return flag; - } - + /// public override bool IsSubsetOf(IPermission target) { @@ -218,21 +261,77 @@ public override bool IsSubsetOf(IPermission target) } return subset; } + + // + // + // + // + // + /// + public override SecurityElement ToXml() + { + Type type = GetType(); + SecurityElement root = new SecurityElement(XmlStr._IPermission); + root.AddAttribute(XmlStr._class, type.AssemblyQualifiedName.Replace('\"', '\'')); + root.AddAttribute(XmlStr._Version, XmlStr._VersionNumber); + if (IsUnrestricted()) + { + root.AddAttribute(XmlStr._Unrestricted, XmlStr._true); + } + else + { + root.AddAttribute(XmlStr._AllowBlankPassword, AllowBlankPassword.ToString(CultureInfo.InvariantCulture)); + + if (_keyvalues != null) + { + foreach (DBConnectionString value in _keyvalues) + { + SecurityElement valueElement = new SecurityElement(XmlStr._add); + string tmp; + + tmp = value.ConnectionString; + tmp = EncodeXmlValue(tmp); + if (!ADP.IsEmpty(tmp)) + { + valueElement.AddAttribute(XmlStr._ConnectionString, tmp); + } + + tmp = value.Restrictions; + tmp = EncodeXmlValue(tmp); + if (tmp == null) + { + tmp = ""; + } + + valueElement.AddAttribute(XmlStr._KeyRestrictions, tmp); + + tmp = value.Behavior.ToString(); + valueElement.AddAttribute(XmlStr._KeyRestrictionBehavior, tmp); + + root.AddChild(valueElement); + } + } + } + return root; + } + /// public override IPermission Union(IPermission target) { if (target == null) { - return this.Copy(); + return Copy(); } - if (target.GetType() != this.GetType()) + + if (target.GetType() != GetType()) { throw ADP.PermissionTypeMismatch(); } + if (IsUnrestricted()) - { // MDAC 84803 - return this.Copy(); + { + return Copy(); } SqlClientPermission newPermission = (SqlClientPermission)target.Copy(); @@ -248,9 +347,47 @@ public override IPermission Union(IPermission target) } } } - return (newPermission.IsEmpty() ? null : newPermission); + + return newPermission.IsEmpty() ? null : newPermission; } + + internal void AddPermissionEntry(DBConnectionString entry) + { + if (_keyvaluetree == null) + { + _keyvaluetree = new NameValuePermission(); + } + + if (_keyvalues == null) + { + _keyvalues = new ArrayList(); + } + + NameValuePermission.AddEntry(_keyvaluetree, _keyvalues, entry); + _IsUnrestricted = false; + } + + #endregion + + #region Private Methods + + // Modified CopyFrom to make sure that we copy the Name Value Pair + private void CopyFrom(SqlClientPermission permission) + { + if (!_IsUnrestricted) + { + if (permission._keyvalues != null) + { + _keyvalues = (ArrayList)permission._keyvalues.Clone(); + if (permission._keyvaluetree != null) + { + _keyvaluetree = permission._keyvaluetree.CopyNameValue(); + } + } + } + } + private string DecodeXmlValue(string value) { if (value != null && (0 < value.Length)) @@ -278,157 +415,43 @@ private string EncodeXmlValue(string value) } return value; } - - // - // - // - /// - public override void FromXml(SecurityElement securityElement) - { - // code derived from CodeAccessPermission.ValidateElement - if (securityElement == null) - { - throw ADP.ArgumentNull("securityElement"); - } - string tag = securityElement.Tag; - if (!tag.Equals(XmlStr._Permission) && !tag.Equals(XmlStr._IPermission)) - { - throw ADP.NotAPermissionElement(); - } - String version = securityElement.Attribute(XmlStr._Version); - if (version != null && !version.Equals(XmlStr._VersionNumber)) - { - throw ADP.InvalidXMLBadVersion(); - } - - string unrestrictedValue = securityElement.Attribute(XmlStr._Unrestricted); - _IsUnrestricted = unrestrictedValue != null && Boolean.Parse(unrestrictedValue); - - Clear(); // MDAC 83105 - if (!_IsUnrestricted) - { - string allowNull = securityElement.Attribute(XmlStr._AllowBlankPassword); - AllowBlankPassword = allowNull != null && Boolean.Parse(allowNull); - - ArrayList children = securityElement.Children; - if (children != null) - { - foreach (SecurityElement keyElement in children) - { - tag = keyElement.Tag; - if (XmlStr._add == tag || (tag != null && XmlStr._add == tag.ToLower(CultureInfo.InvariantCulture))) - { - string constr = keyElement.Attribute(XmlStr._ConnectionString); - string restrt = keyElement.Attribute(XmlStr._KeyRestrictions); - string behavr = keyElement.Attribute(XmlStr._KeyRestrictionBehavior); - - KeyRestrictionBehavior behavior = KeyRestrictionBehavior.AllowOnly; - if (behavr != null) - { - behavior = (KeyRestrictionBehavior)Enum.Parse(typeof(KeyRestrictionBehavior), behavr, true); - } - constr = DecodeXmlValue(constr); - restrt = DecodeXmlValue(restrt); - Add(constr, restrt, behavior); - } - } - } - } - else - { - AllowBlankPassword = false; - } - } - - // - // - // - // - // - /// - public override SecurityElement ToXml() + + private bool IsEmpty() { - Type type = this.GetType(); - SecurityElement root = new SecurityElement(XmlStr._IPermission); - root.AddAttribute(XmlStr._class, type.AssemblyQualifiedName.Replace('\"', '\'')); - root.AddAttribute(XmlStr._Version, XmlStr._VersionNumber); - - if (IsUnrestricted()) - { - root.AddAttribute(XmlStr._Unrestricted, XmlStr._true); - } - else - { - root.AddAttribute(XmlStr._AllowBlankPassword, AllowBlankPassword.ToString(CultureInfo.InvariantCulture)); - - if (_keyvalues != null) - { - foreach (DBConnectionString value in _keyvalues) - { - SecurityElement valueElement = new SecurityElement(XmlStr._add); - string tmp; - - tmp = value.ConnectionString; // WebData 97375 - tmp = EncodeXmlValue(tmp); - if (!ADP.IsEmpty(tmp)) - { - valueElement.AddAttribute(XmlStr._ConnectionString, tmp); - } - tmp = value.Restrictions; - tmp = EncodeXmlValue(tmp); - if (tmp == null) - { - tmp = ""; - } - valueElement.AddAttribute(XmlStr._KeyRestrictions, tmp); - - tmp = value.Behavior.ToString(); - valueElement.AddAttribute(XmlStr._KeyRestrictionBehavior, tmp); - - root.AddChild(valueElement); - } - } - } - return root; + ArrayList keyvalues = _keyvalues; + bool flag = !IsUnrestricted() && !AllowBlankPassword && (keyvalues == null || (0 == keyvalues.Count)); + return flag; } + + #endregion - private sealed class NameValuePermission : IComparable + private sealed 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; + // Reused as both key and value nodes: + // Key nodes link to value nodes. + // Value nodes link to key nodes. + private readonly string _value; // value node with (_restrictions != null) 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 static readonly NameValuePermission Default = null; 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 + { + // deep-copy _value = permit._value; _entry = permit._entry; _tree = permit._tree; if (_tree != null) { - NameValuePermission[] tree = (_tree.Clone() as NameValuePermission[]); + NameValuePermission[] tree = _tree.Clone() as NameValuePermission[]; for (int i = 0; i < tree.Length; ++i) { if (tree[i] != null) @@ -439,13 +462,24 @@ private NameValuePermission(NameValuePermission permit) _tree = tree; } } + + private NameValuePermission(string keyword) + { + _value = keyword; + } - int IComparable.CompareTo(object a) + private NameValuePermission(string value, DBConnectionString entry) + { + _value = value; + _entry = entry; + } + + int IComparable.CompareTo(NameValuePermission other) { - return StringComparer.Ordinal.Compare(_value, ((NameValuePermission)a)._value); + return StringComparer.Ordinal.Compare(_value, other._value); } - static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) + internal static void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) { Debug.Assert(entry != null, "null DBConnectionString"); @@ -453,14 +487,13 @@ static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBC { for (NameValuePair keychain = entry.KeyChain; keychain != null; keychain = keychain.Next) { - NameValuePermission kv; - - kv = kvtree.CheckKeyForValue(keychain.Name); + NameValuePermission kv = kvtree.CheckKeyForValue(keychain.Name); if (kv == null) { kv = new NameValuePermission(keychain.Name); kvtree.Add(kv); // add directly into live tree } + kvtree = kv; kv = kvtree.CheckKeyForValue(keychain.Value); @@ -475,7 +508,8 @@ static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBC } } else if (keychain.Next == null) - { // shorter chain potential + { + // shorter chain potential if (kv._entry != null) { Debug.Assert(entries.Contains(kv._entry), "entries doesn't contain entry"); @@ -492,7 +526,8 @@ static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBC } } else - { // global restrictions, MDAC 84443 + { + // global restrictions DBConnectionString kentry = kvtree._entry; if (kentry != null) { @@ -504,10 +539,85 @@ static internal void AddEntry(NameValuePermission kvtree, ArrayList entries, DBC { kvtree._entry = entry; } + entries.Add(kvtree._entry); } } + internal bool CheckValueForKeyPermit(DBConnectionString parsetable) + { + if (parsetable == null) + { + return false; + } + + bool hasMatch = false; + NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it + if (keytree != null) + { + hasMatch = parsetable.IsEmpty; // MDAC 86773 + if (!hasMatch) + { + // which key do we follow the key-value chain on + foreach (var permitKey in keytree) + { + if (permitKey != null) + { + string keyword = permitKey._value; + + Debug.Assert(permitKey._entry == null, "key member has no restrictions"); + if (parsetable.ContainsKey(keyword)) + { + string valueInQuestion = (string)parsetable[keyword]; + + // keyword is restricted to certain values + NameValuePermission permitValue = permitKey.CheckKeyForValue(valueInQuestion); + if (permitValue != null) + { + //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 safely 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; + } + } + } + } + } + // partial chain match, either leaf-node by shorter chain or fail mid-chain if ( _restrictions == null) + } + + DBConnectionString entry = _entry; + if (entry != null) + { + // also checking !hasMatch is tempting, but wrong + // user can safely 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); + } + + // mid-chain failure + return hasMatch; + } + + internal NameValuePermission CopyNameValue() + { + return new NameValuePermission(this); + } + internal void Intersect(ArrayList entries, NameValuePermission target) { if (target == null) @@ -564,7 +674,7 @@ internal void Intersect(ArrayList entries, NameValuePermission target) } } } - + private void Add(NameValuePermission permit) { NameValuePermission[] tree = _tree; @@ -578,87 +688,15 @@ private void Add(NameValuePermission permit) Array.Sort(newtree); _tree = newtree; } - - internal bool CheckValueForKeyPermit(DBConnectionString parsetable) - { - if (parsetable == null) - { - return false; - } - bool hasMatch = false; - NameValuePermission[] keytree = _tree; // _tree won't mutate but Add will replace it - if (keytree != null) - { - 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 (permitKey != null) - { - string keyword = permitKey._value; - #if DEBUG - Debug.Assert(permitKey._entry == null, "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 (permitValue != null) - { - //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 safely 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 ( _restrictions == null) - } - - DBConnectionString entry = _entry; - if (entry != null) - { - // also checking !hasMatch is tempting, but wrong - // user can safely 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 (valuetree != null) { - for (int i = 0; i < valuetree.Length; ++i) + foreach (var permitValue in valuetree) { - NameValuePermission permitValue = valuetree[i]; - if (String.Equals(keyInQuestion, permitValue._value, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(keyInQuestion, permitValue._value, StringComparison.OrdinalIgnoreCase)) { return permitValue; } @@ -666,14 +704,8 @@ private NameValuePermission CheckKeyForValue(string keyInQuestion) } return null; } - - internal NameValuePermission CopyNameValue() - { - return new NameValuePermission(this); - } } - private static class XmlStr { internal const string _class = "class"; From 90a2beba7d429f1cb38ca61c7ff7bfbb514a42ae Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Apr 2025 13:26:17 -0500 Subject: [PATCH 5/7] It's always bad practice to write your own escape/unescape logic for xml --- .../SqlClient/SqlClientPermission.netfx.cs | 83 +++++++------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index 2311e9ef16..aea2179c94 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -9,6 +9,7 @@ using System.Data; using System.Diagnostics; using System.Globalization; +using System.Net; using System.Reflection; using System.Security; using System.Security.Permissions; @@ -23,8 +24,9 @@ public sealed class SqlClientPermission : DBDataPermission { #region Member Variables + // @TODO: Replace ArrayList with a typed list. private NameValuePermission _keyvaluetree = NameValuePermission.Default; - private ArrayList _keyvalues;; + private ArrayList _keyvalues; #endregion @@ -82,18 +84,19 @@ private SqlClientPermission(SqlClientPermission permission) : base(permission) private bool _IsUnrestricted { + get + { + return base.IsUnrestricted(); + } + set { // Use Reflection to access the base class _isUnrestricted. There is no other way to alter this externally. - FieldInfo fieldInfo = GetType().BaseType.GetField("_isUnrestricted", BindingFlags.Instance - | BindingFlags.NonPublic); + FieldInfo fieldInfo = GetType().BaseType.GetField( + "_isUnrestricted", + BindingFlags.Instance | BindingFlags.NonPublic); fieldInfo.SetValue(this, value); } - - get - { - return base.IsUnrestricted(); - } } #endregion @@ -113,12 +116,14 @@ public override IPermission Copy() return new SqlClientPermission(this); } - // - // - // /// public override void FromXml(SecurityElement securityElement) { + // Reads an XML tree like: + // + // + // + // code derived from CodeAccessPermission.ValidateElement if (securityElement == null) { @@ -163,8 +168,9 @@ public override void FromXml(SecurityElement securityElement) { behavior = (KeyRestrictionBehavior)Enum.Parse(typeof(KeyRestrictionBehavior), behavr, true); } - constr = DecodeXmlValue(constr); - restrt = DecodeXmlValue(restrt); + + constr = WebUtility.HtmlDecode(constr); + restrt = WebUtility.HtmlDecode(restrt); Add(constr, restrt, behavior); } } @@ -262,14 +268,16 @@ public override bool IsSubsetOf(IPermission target) return subset; } - // - // - // - // - // /// public override SecurityElement ToXml() { + // Generates an XML tree like: + // + // + // + // + // + Type type = GetType(); SecurityElement root = new SecurityElement(XmlStr._IPermission); root.AddAttribute(XmlStr._class, type.AssemblyQualifiedName.Replace('\"', '\'')); @@ -290,20 +298,13 @@ public override SecurityElement ToXml() SecurityElement valueElement = new SecurityElement(XmlStr._add); string tmp; - tmp = value.ConnectionString; - tmp = EncodeXmlValue(tmp); + tmp = SecurityElement.Escape(value.ConnectionString); if (!ADP.IsEmpty(tmp)) { valueElement.AddAttribute(XmlStr._ConnectionString, tmp); } - tmp = value.Restrictions; - tmp = EncodeXmlValue(tmp); - if (tmp == null) - { - tmp = ""; - } - + tmp = SecurityElement.Escape(value.Restrictions) ?? ""; valueElement.AddAttribute(XmlStr._KeyRestrictions, tmp); tmp = value.Behavior.ToString(); @@ -388,34 +389,6 @@ private void CopyFrom(SqlClientPermission permission) } } - private string DecodeXmlValue(string value) - { - if (value != null && (0 < value.Length)) - { - value = value.Replace(""", "\""); - value = value.Replace("'", "\'"); - value = value.Replace("<", "<"); - value = value.Replace(">", ">"); - value = value.Replace("&", "&"); - } - return value; - } - - private string EncodeXmlValue(string value) - { - if (value != null && (0 < value.Length)) - { - value = value.Replace('\0', ' '); // assumption that '\0' will only be at end of string - value = value.Trim(); - value = value.Replace("&", "&"); - value = value.Replace(">", ">"); - value = value.Replace("<", "<"); - value = value.Replace("\'", "'"); - value = value.Replace("\"", """); - } - return value; - } - private bool IsEmpty() { ArrayList keyvalues = _keyvalues; From 83d7846b29c09adca7dcfd5d761bdceb0f5f021b Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 15 Apr 2025 16:44:19 -0500 Subject: [PATCH 6/7] Reintroduce serializable attribute and generic IComparable --- .../Data/SqlClient/SqlClientPermission.netfx.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index aea2179c94..df7d15ea5d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -398,7 +398,8 @@ private bool IsEmpty() #endregion - private sealed class NameValuePermission : IComparable + [Serializable] + private sealed class NameValuePermission : IComparable { // Reused as both key and value nodes: // Key nodes link to value nodes. @@ -447,10 +448,8 @@ private NameValuePermission(string value, DBConnectionString entry) _entry = entry; } - int IComparable.CompareTo(NameValuePermission other) - { - return StringComparer.Ordinal.Compare(_value, other._value); - } + int IComparable.CompareTo(object other) => + string.CompareOrdinal(_value, ((NameValuePermission)other)._value); internal static void AddEntry(NameValuePermission kvtree, ArrayList entries, DBConnectionString entry) { From beb90140b17ee459e556abc292cd6e586700b1e8 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 16 Apr 2025 18:10:16 -0500 Subject: [PATCH 7/7] What. --- .../src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs index df7d15ea5d..2b0d7ef50e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientPermission.netfx.cs @@ -299,7 +299,7 @@ public override SecurityElement ToXml() string tmp; tmp = SecurityElement.Escape(value.ConnectionString); - if (!ADP.IsEmpty(tmp)) + if (!string.IsNullOrEmpty(tmp)) { valueElement.AddAttribute(XmlStr._ConnectionString, tmp); }