1 //------------------------------------------------------------------------------
2 // <copyright file="WebPermission.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 
8 namespace System.Net {
9 
10     using System.Collections;
11     using System.Security;
12     using System.Security.Permissions;
13     using System.Text.RegularExpressions;
14     using System.Globalization;
15     using System.Runtime.Serialization;
16 
17     //NOTE: While WebPermissionAttribute resides in System.DLL,
18     //      no classes from that DLL are able to make declarative usage of WebPermission.
19 
20 
21     // THE syntax of this attribute is as followed
22     // [WebPermission(SecurityAction.Assert, Connect="http://hostname/path/url", Accept="http://localhost/path/url")]
23     // [WebPermission(SecurityAction.Assert, ConnectPattern="http://hostname/www\.microsoft\.*/url/*", AcceptPattern="http://localhost/*")]
24 
25     // WHERE:
26     //=======
27     // - 'Connect' and 'Accept' keywords allow you to specify the final URI
28     // - 'ConnectPattern' and 'AcceptPattern' keywords allow you to specify a set of URI in escaped Regex form
29     // -           They take '.*' as special "everything" indicators, which are fast-pathed.
30 
31     [   AttributeUsage( AttributeTargets.Method | AttributeTargets.Constructor |
32                         AttributeTargets.Class  | AttributeTargets.Struct      |
33                         AttributeTargets.Assembly,
34                         AllowMultiple = true, Inherited = false )]
35 
36     [Serializable()] sealed public class WebPermissionAttribute: CodeAccessSecurityAttribute
37     {
38         private object m_accept  = null;
39         private object m_connect = null;
40 
WebPermissionAttribute( SecurityAction action )41         public WebPermissionAttribute( SecurityAction action ): base( action )
42         {
43         }
44 
45         public string Connect {
46             get { return m_connect as string;}
47             set {
48                 if (m_connect != null) {
49                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "Connect", value), "value");
50                 }
51                 m_connect = value;
52             }
53         }
54 
55         public string Accept {
56             get { return m_accept as string; }
57             set {
58                 if (m_accept != null) {
59                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "Accept", value), "value");
60                 }
61                 m_accept = value;
62             }
63         }
64 
65         public string ConnectPattern {
66             get
67             {
68                 return m_connect is DelayedRegex ? m_connect.ToString() : m_connect is bool && (bool) m_connect ? WebPermission.MatchAll : null;
69             }
70 
71             set {
72                 if (m_connect != null) {
73                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "ConnectPatern", value), "value");
74                 }
75                 if (value == WebPermission.MatchAll)
76                 {
77                     m_connect = true;
78                 }
79                 else
80                 {
81                     m_connect = new DelayedRegex(value);
82                 }
83             }
84         }
85 
86         public string AcceptPattern {
87             get
88             {
89                 return m_accept is DelayedRegex ? m_accept.ToString() : m_accept is bool && (bool) m_accept ? WebPermission.MatchAll : null;
90             }
91 
92             set
93             {
94                 if (m_accept != null) {
95                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "AcceptPattern", value), "value");
96                 }
97                 if (value == WebPermission.MatchAll)
98                 {
99                     m_accept = true;
100                 }
101                 else
102                 {
103                     m_accept = new DelayedRegex(value);
104                 }
105             }
106         }
107 
108 /*
109         public bool ConnectAll
110         {
111             get
112             {
113                 return m_connect is bool ? (bool) m_connect : false;
114             }
115 
116             set
117             {
118                 if (m_connect != null)
119                 {
120                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "ConnectAll", value), "value");
121                 }
122                 m_connect = value;
123             }
124         }
125 
126         public bool AcceptAll
127         {
128             get
129             {
130                 return m_accept is bool ? (bool) m_accept : false;
131             }
132 
133             set
134             {
135                 if (m_accept != null)
136                 {
137                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, "AcceptAll", value), "value");
138                 }
139                 m_accept = value;
140             }
141         }
142 */
143 
CreatePermission()144         public override IPermission CreatePermission()
145         {
146             WebPermission perm = null;
147             if (Unrestricted) {
148                 perm = new WebPermission( PermissionState.Unrestricted);
149             }
150             else {
151                 NetworkAccess access = (NetworkAccess) 0;
152                 if (m_connect is bool)
153                 {
154                     if ((bool) m_connect)
155                     {
156                         access |= NetworkAccess.Connect;
157                     }
158                     m_connect = null;
159                 }
160                 if (m_accept is bool)
161                 {
162                     if ((bool) m_accept)
163                     {
164                         access |= NetworkAccess.Accept;
165                     }
166                     m_accept = null;
167                 }
168                 perm = new WebPermission(access);
169                 if (m_accept != null) {
170                     if (m_accept is DelayedRegex) {
171                         perm.AddAsPattern(NetworkAccess.Accept, (DelayedRegex)m_accept);
172                     }
173                     else {
174                         perm.AddPermission(NetworkAccess.Accept, (string)m_accept);
175                     }
176                 }
177                 if (m_connect != null) {
178                     if (m_connect is DelayedRegex) {
179                         perm.AddAsPattern(NetworkAccess.Connect, (DelayedRegex)m_connect);
180                     }
181                     else {
182                         perm.AddPermission(NetworkAccess.Connect, (string)m_connect);
183                     }
184                 }
185             }
186             return perm;
187         }
188 
189     }
190 
191     [Serializable]
192     internal class DelayedRegex
193     {
194         private Regex   _AsRegex;
195         private string  _AsString;
196 
DelayedRegex(string regexString)197         internal DelayedRegex(string regexString)
198         {
199             if (regexString == null)
200                 throw new ArgumentNullException("regexString");
201 
202             _AsString = regexString;
203         }
204 
DelayedRegex(Regex regex)205         internal DelayedRegex(Regex regex)
206         {
207             if (regex == null)
208                 throw new ArgumentNullException("regex");
209 
210             _AsRegex = regex;
211         }
212 
213         internal Regex AsRegex
214         {
215             get
216             {
217                 if (_AsRegex == null)
218                 {
219                     _AsRegex = new Regex(_AsString + "[/]?", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant);
220                 }
221                 return _AsRegex;
222             }
223         }
224 
ToString()225         public override string ToString()
226         {
227             return _AsString != null ? _AsString : (_AsString = _AsRegex.ToString());
228         }
229     }
230 
231     /// <devdoc>
232     ///    <para>
233     ///       Controls rights to make or accept connections on a Web address.
234     ///    </para>
235     /// </devdoc>
236     [Serializable]
237     public sealed class WebPermission : CodeAccessPermission, IUnrestrictedPermission {
238 
239         private bool m_noRestriction;
240         [OptionalField] private bool m_UnrestrictedConnect;
241         [OptionalField] private bool m_UnrestrictedAccept;
242         private ArrayList m_connectList = new ArrayList();
243         private ArrayList m_acceptList = new ArrayList();
244 
245         internal const string MatchAll = ".*";
246         private static volatile Regex s_MatchAllRegex;
247         internal static Regex MatchAllRegex
248         {
249             get
250             {
251                 if (s_MatchAllRegex == null)
252                 {
253                     s_MatchAllRegex = new Regex(".*");
254                 }
255                 return s_MatchAllRegex;
256             }
257         }
258 
259         /// <devdoc>
260         ///    <para>
261         ///       Returns the enumeration of permissions to connect a remote URI.
262         ///    </para>
263         /// </devdoc>
264         public IEnumerator ConnectList {
265             get {
266                 if (m_UnrestrictedConnect)
267                 {
268                     return (new Regex[] { MatchAllRegex }).GetEnumerator();
269                 }
270 
271                 ArrayList cloned = new ArrayList(m_connectList.Count);
272 
273                 for (int i = 0; i < m_connectList.Count; ++i)
274                     cloned.Add(m_connectList[i] is DelayedRegex? (object)((DelayedRegex)m_connectList[i]).AsRegex :
275                     m_connectList[i] is Uri? (object)((Uri)m_connectList[i]).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped) :
276                     m_connectList[i]);
277 
278                 return cloned.GetEnumerator();
279             }
280         }
281 
282         /// <devdoc>
283         ///    <para>
284         ///       Returns the enumeration of permissions to export a local URI.
285         ///    </para>
286         /// </devdoc>
287         public IEnumerator AcceptList {
288             get {
289                 if (m_UnrestrictedAccept)
290                 {
291                     return (new Regex[] { MatchAllRegex }).GetEnumerator();
292                 }
293 
294                 ArrayList cloned = new ArrayList(m_acceptList.Count);
295 
296                 for (int i = 0; i < m_acceptList.Count; ++i)
297                     cloned.Add(m_acceptList[i] is DelayedRegex? (object)((DelayedRegex)m_acceptList[i]).AsRegex :
298                     m_acceptList[i] is Uri? (object)((Uri)m_acceptList[i]).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped) :
299                     m_acceptList[i]);
300 
301                 return cloned.GetEnumerator();
302             }
303         }
304 
305         /// <devdoc>
306         ///    <para>
307         ///       Creates a new instance of the <see cref='System.Net.WebPermission'/>
308         ///       class that passes all demands or
309         ///       that fails all demands.
310         ///    </para>
311         /// </devdoc>
WebPermission(PermissionState state)312         public WebPermission(PermissionState state) {
313             m_noRestriction = (state == PermissionState.Unrestricted);
314         }
315 
WebPermission(bool unrestricted)316         internal WebPermission(bool unrestricted) {
317             m_noRestriction = unrestricted;
318         }
319 
320         /// <devdoc>
321         ///    <para>
322         ///       Creates a new instance of the <see cref='System.Net.WebPermission'/> class.
323         ///    </para>
324         /// </devdoc>
WebPermission()325         public WebPermission() {
326         }
327 
WebPermission(NetworkAccess access)328         internal WebPermission(NetworkAccess access)
329         {
330             m_UnrestrictedConnect = (access & NetworkAccess.Connect) != 0;
331             m_UnrestrictedAccept = (access & NetworkAccess.Accept) != 0;
332         }
333 
334         /// <devdoc>
335         ///    <para>
336         ///       Creates a new instance of the <see cref='System.Net.WebPermission'/>
337         ///       class with the specified access rights for
338         ///       the specified URI Pattern.
339         ///       Suitable only for WebPermission policy object construction
340         ///    </para>
341         /// </devdoc>
WebPermission(NetworkAccess access, Regex uriRegex)342         public WebPermission(NetworkAccess access, Regex uriRegex) {
343             AddPermission(access, uriRegex);
344         }
345 
346         /// <devdoc>
347         ///    <para>
348         ///       Creates a new instance of the <see cref='System.Net.WebPermission'/>
349         ///       class with the specified access rights for
350         ///       the specified Uniform Resource Identifier .
351         ///       Suitable for requesting particular WebPermission
352         ///    </para>
353         /// </devdoc>
354         // <
WebPermission(NetworkAccess access, String uriString)355         public WebPermission(NetworkAccess access, String uriString) {
356             AddPermission(access, uriString);
357         }
358         //
359         // <
WebPermission(NetworkAccess access, Uri uri)360         internal WebPermission(NetworkAccess access, Uri uri) {
361             AddPermission(access, uri);
362         }
363 
364         // Methods specific to this class
365         /// <devdoc>
366         ///   <para>
367         ///      Adds a new instance of the WebPermission
368         ///      class with the specified access rights for the particular Uniform Resource Identifier.
369         ///    </para>
370         /// </devdoc>
371         // <
AddPermission(NetworkAccess access, String uriString)372         public void AddPermission(NetworkAccess access, String  uriString) {
373             if (uriString == null) {
374                 throw new ArgumentNullException("uriString");
375             }
376 
377             if (m_noRestriction)
378             {
379                 return;
380             }
381 
382             Uri uri;
383             if (Uri.TryCreate(uriString, UriKind.Absolute, out uri))
384                 AddPermission(access, uri);
385             else
386             {
387                 ArrayList lists = new ArrayList();
388                 if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect)
389                     lists.Add(m_connectList);
390                 if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept)
391                     lists.Add(m_acceptList);
392 
393                 foreach (ArrayList list in lists)
394                 {
395                     // avoid duplicated uris in the list
396                     bool found = false;
397                     foreach (object obj in list) {
398                         string str = obj as string;
399                         if (str != null && string.Compare(str, uriString, StringComparison.OrdinalIgnoreCase ) == 0)
400                         {
401                             found = true;
402                             break;
403                         }
404                     }
405 
406                     if (!found) {
407                         list.Add(uriString);
408                     }
409                 }
410             }
411         }
412 
413         // <
AddPermission(NetworkAccess access, Uri uri)414         internal void AddPermission(NetworkAccess access, Uri uri) {
415             if (uri == null) {
416                 throw new ArgumentNullException("uri");
417             }
418 
419             if (m_noRestriction)
420             {
421                 return;
422             }
423 
424             ArrayList lists = new ArrayList();
425             if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect)
426                 lists.Add(m_connectList);
427             if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept)
428                 lists.Add(m_acceptList);
429 
430             foreach (ArrayList list in lists)
431             {
432                 // avoid duplicated uris in the list
433                 bool found = false;
434                 foreach (object permObj in list) {
435                     if ((permObj is Uri) && uri.Equals(permObj))
436                     {
437                         found = true;
438                         break;
439                     }
440                 }
441                 if (!found) {
442                     list.Add(uri);
443                 }
444             }
445         }
446 
447         /// <devdoc>
448         /// <para>Adds a new instance of the <see cref='System.Net.WebPermission'/>
449         /// class with the specified access rights for the specified URI Pattern.
450         /// Should be used during a policy object creation and not for particular URI permission check</para>
451         /// </devdoc>
AddPermission(NetworkAccess access, Regex uriRegex)452         public void AddPermission(NetworkAccess access, Regex uriRegex) {
453             if (uriRegex == null) {
454                 throw new ArgumentNullException("uriRegex");
455             }
456 
457             if (m_noRestriction)
458             {
459                 return;
460             }
461 
462             if (uriRegex.ToString() == MatchAll)
463             {
464                 if (!m_UnrestrictedConnect && (access & NetworkAccess.Connect) != 0)
465                 {
466                     m_UnrestrictedConnect = true;
467                     m_connectList.Clear();
468                 }
469                 if (!m_UnrestrictedAccept && (access & NetworkAccess.Accept) != 0)
470                 {
471                     m_UnrestrictedAccept = true;
472                     m_acceptList.Clear();
473                 }
474                 return;
475             }
476 
477             AddAsPattern(access, new DelayedRegex(uriRegex));
478         }
479 
480         //  Overloaded form using string inputs
481         //  Enforces case-insensitive matching
482         /// Adds a new instance of the System.Net.WebPermission
483         /// class with the specified access rights for the specified URI Pattern
AddAsPattern(NetworkAccess access, DelayedRegex uriRegexPattern)484         internal void AddAsPattern(NetworkAccess access, DelayedRegex uriRegexPattern)
485         {
486             ArrayList lists = new ArrayList();
487             if ((access & NetworkAccess.Connect) != 0 && !m_UnrestrictedConnect)
488                 lists.Add(m_connectList);
489             if ((access & NetworkAccess.Accept) != 0 && !m_UnrestrictedAccept)
490                 lists.Add(m_acceptList);
491 
492             foreach (ArrayList list in lists)
493             {
494                 // avoid duplicated regexes in the list
495                 bool found = false;
496                 foreach (object obj in list) {
497                     if ((obj is DelayedRegex) && (string.Compare(uriRegexPattern.ToString(), obj.ToString(), StringComparison.OrdinalIgnoreCase ) == 0)) {
498                         found = true;
499                         break;
500                     }
501                 }
502 
503                 if (!found) {
504                     list.Add(uriRegexPattern);
505                 }
506             }
507         }
508 
509         // IUnrestrictedPermission interface methods
510         /// <devdoc>
511         ///    <para>
512         ///       Checks the overall permisison state of the object.
513         ///    </para>
514         /// </devdoc>
IsUnrestricted()515         public bool IsUnrestricted() {
516             return m_noRestriction;
517         }
518 
519         // IPermission interface methods
520         /// <devdoc>
521         ///    <para>
522         ///       Creates a copy of a <see cref='System.Net.WebPermission'/> instance.
523         ///    </para>
524         /// </devdoc>
Copy()525         public override IPermission Copy() {
526             if (m_noRestriction)
527             {
528                 return new WebPermission(true);
529             }
530 
531             WebPermission wp = new WebPermission((m_UnrestrictedConnect ? NetworkAccess.Connect : (NetworkAccess) 0) |
532                 (m_UnrestrictedAccept ? NetworkAccess.Accept : (NetworkAccess)0));
533             wp.m_acceptList = (ArrayList)m_acceptList.Clone();
534             wp.m_connectList = (ArrayList)m_connectList.Clone();
535             return wp;
536         }
537 
538         /// <devdoc>
539         /// <para>Compares two <see cref='System.Net.WebPermission'/> instances.</para>
540         /// </devdoc>
IsSubsetOf(IPermission target)541         public override bool IsSubsetOf(IPermission target) {
542             // Pattern suggested by security engine
543             if (target == null) {
544                 return !m_noRestriction && !m_UnrestrictedConnect && !m_UnrestrictedAccept && m_connectList.Count == 0 && m_acceptList.Count == 0;
545             }
546 
547             WebPermission other = target as WebPermission;
548             if (other == null) {
549                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
550             }
551 
552             if (other.m_noRestriction)
553             {
554                 return true;
555             }
556             else if (m_noRestriction)
557             {
558                 return false;
559             }
560 
561             //
562             // Besides SPECIAL case, this method is restricted to only final URIs (strings) on
563             // the current object.
564             // The restriction comes from the problem of finding a Regex to be a subset of another Regex
565             //
566             DelayedRegex regex = null;
567 
568             if (!other.m_UnrestrictedAccept)
569             {
570                 if (m_UnrestrictedAccept)
571                 {
572                     return false;
573                 }
574                 else if (m_acceptList.Count != 0)
575                 {
576                     if (other.m_acceptList.Count == 0)
577                     {
578                         return false;
579                     }
580                     foreach(object obj in this.m_acceptList) {
581                         regex = obj as DelayedRegex;
582                         if(regex != null) {
583                             if(isSpecialSubsetCase(obj.ToString(), other.m_acceptList))
584                                 continue;
585                             throw new NotSupportedException(SR.GetString(SR.net_perm_both_regex));
586                         }
587                         if(!isMatchedURI(obj, other.m_acceptList))
588                             return false;
589                     }
590                 }
591             }
592 
593             if (!other.m_UnrestrictedConnect)
594             {
595                 if (m_UnrestrictedConnect)
596                 {
597                     return false;
598                 }
599                 else if (m_connectList.Count != 0)
600                 {
601                     if (other.m_connectList.Count == 0)
602                     {
603                         return false;
604                     }
605                     foreach(object obj in this.m_connectList) {
606                         regex = obj as DelayedRegex;
607                         if(regex != null) {
608                             if(isSpecialSubsetCase(obj.ToString(), other.m_connectList))
609                                 continue;
610                             throw new NotSupportedException(SR.GetString(SR.net_perm_both_regex));
611                         }
612                         if(!isMatchedURI(obj, other.m_connectList))
613                             return false;
614                     }
615                 }
616             }
617 
618             return true;
619         }
620 
621         //Checks special case when testing Regex to be a subset of other Regex
622         //Support only the case when  both Regexes are identical as strings.
isSpecialSubsetCase(String regexToCheck, ArrayList permList)623         private static bool isSpecialSubsetCase(String regexToCheck, ArrayList permList) {
624 
625             Uri uri;
626             foreach(object uriPattern in permList) {
627                 DelayedRegex regex = uriPattern as DelayedRegex;
628                 if(regex != null) {
629                     //regex parameter against regex permission
630                     if (String.Compare(regexToCheck, regex.ToString(), StringComparison.OrdinalIgnoreCase ) == 0)
631                         return true;
632                 }
633                 else if ((uri = uriPattern as Uri) != null) {
634                     //regex parameter against Uri permission
635                     if (String.Compare(regexToCheck, Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped)), StringComparison.OrdinalIgnoreCase ) == 0)
636                         return true;
637                 }
638                 else if (String.Compare(regexToCheck, Regex.Escape(uriPattern.ToString()), StringComparison.OrdinalIgnoreCase ) == 0) {
639                    //regex parameter against string permission
640                    return true;
641                 }
642 
643             }
644 
645             return false;
646        }
647 
648         // The union of two web permissions is formed by concatenating
649         // the list of allowed regular expressions. There is no check
650         // for duplicates/overlaps
651         /// <devdoc>
652         /// <para>Returns the logical union between two <see cref='System.Net.WebPermission'/> instances.</para>
653         /// </devdoc>
Union(IPermission target)654         public override IPermission Union(IPermission target) {
655             // Pattern suggested by Security engine
656             if (target==null) {
657                 return this.Copy();
658             }
659             WebPermission other = target as WebPermission;
660             if(other == null) {
661                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
662             }
663 
664             if (m_noRestriction || other.m_noRestriction)
665             {
666                 return new WebPermission(true);
667             }
668 
669             WebPermission result = new WebPermission();
670 
671             if (m_UnrestrictedConnect || other.m_UnrestrictedConnect)
672             {
673                 result.m_UnrestrictedConnect = true;
674             }
675             else
676             {
677                 result.m_connectList = (ArrayList) other.m_connectList.Clone();
678 
679                 for (int i = 0; i < m_connectList.Count; i++) {
680                     DelayedRegex uriPattern = m_connectList[i] as DelayedRegex;
681                     if(uriPattern == null)
682                         if (m_connectList[i] is string)
683                             result.AddPermission(NetworkAccess.Connect, (string)m_connectList[i]);
684                         else
685                             result.AddPermission(NetworkAccess.Connect, (Uri)m_connectList[i]);
686                     else
687                         result.AddAsPattern(NetworkAccess.Connect, uriPattern);
688                 }
689             }
690 
691             if (m_UnrestrictedAccept || other.m_UnrestrictedAccept)
692             {
693                 result.m_UnrestrictedAccept = true;
694             }
695             else
696             {
697                 result.m_acceptList = (ArrayList) other.m_acceptList.Clone();
698 
699                 for (int i = 0; i < m_acceptList.Count; i++) {
700                     DelayedRegex uriPattern = m_acceptList[i] as DelayedRegex;
701                     if(uriPattern == null)
702                         if (m_acceptList[i] is string)
703                             result.AddPermission(NetworkAccess.Accept, (string)m_acceptList[i]);
704                         else
705                             result.AddPermission(NetworkAccess.Accept, (Uri)m_acceptList[i]);
706                     else
707                         result.AddAsPattern(NetworkAccess.Accept, uriPattern);
708                 }
709             }
710 
711             return result;
712         }
713 
714         /// <devdoc>
715         /// <para>Returns the logical intersection between two <see cref='System.Net.WebPermission'/> instances.</para>
716         /// </devdoc>
Intersect(IPermission target)717         public override IPermission Intersect(IPermission target) {
718             // Pattern suggested by Security engine
719             if (target == null) {
720                 return null;
721             }
722 
723             WebPermission other = target as WebPermission;
724             if(other == null) {
725                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
726             }
727 
728             if (m_noRestriction)
729             {
730                 return other.Copy();
731             }
732             if (other.m_noRestriction)
733             {
734                 return Copy();
735             }
736 
737             WebPermission result = new WebPermission();
738 
739             if (m_UnrestrictedConnect && other.m_UnrestrictedConnect)
740             {
741                 result.m_UnrestrictedConnect = true;
742             }
743             else if (m_UnrestrictedConnect || other.m_UnrestrictedConnect)
744             {
745                 result.m_connectList = (ArrayList) (m_UnrestrictedConnect ? other : this).m_connectList.Clone();
746             }
747             else
748             {
749                 intersectList(m_connectList, other.m_connectList, result.m_connectList);
750             }
751 
752             if (m_UnrestrictedAccept && other.m_UnrestrictedAccept)
753             {
754                 result.m_UnrestrictedAccept = true;
755             }
756             else if (m_UnrestrictedAccept || other.m_UnrestrictedAccept)
757             {
758                 result.m_acceptList = (ArrayList) (m_UnrestrictedAccept ? other : this).m_acceptList.Clone();
759             }
760             else
761             {
762                 intersectList(m_acceptList, other.m_acceptList, result.m_acceptList);
763             }
764 
765             // return null if resulting permission is restricted and empty
766             if (!result.m_UnrestrictedConnect && !result.m_UnrestrictedAccept &&
767                 result.m_connectList.Count == 0 && result.m_acceptList.Count == 0) {
768                 return null;
769             }
770             return result;
771         }
772 
773         /// <devdoc>
774         /// </devdoc>
FromXml(SecurityElement securityElement)775         public override void FromXml(SecurityElement securityElement) {
776             if (securityElement == null) {
777 
778                 //
779                 // null SecurityElement
780                 //
781 
782                 throw new ArgumentNullException("securityElement");
783             }
784             if (!securityElement.Tag.Equals("IPermission")) {
785 
786                 //
787                 // SecurityElement must be a permission element
788                 //
789 
790                 throw new ArgumentException(SR.GetString(SR.net_not_ipermission), "securityElement");
791             }
792 
793             string className = securityElement.Attribute("class");
794 
795             if (className == null) {
796 
797                 //
798                 // SecurityElement must be a permission element for this type
799                 //
800 
801                 throw new ArgumentException(SR.GetString(SR.net_no_classname), "securityElement");
802             }
803             if (className.IndexOf(this.GetType().FullName) < 0) {
804 
805                 //
806                 // SecurityElement must be a permission element for this type
807                 //
808 
809                 throw new ArgumentException(SR.GetString(SR.net_no_typename), "securityElement");
810             }
811 
812             String str = securityElement.Attribute("Unrestricted");
813 
814             m_connectList = new ArrayList();
815             m_acceptList = new ArrayList();
816             m_UnrestrictedAccept = m_UnrestrictedConnect = false;
817 
818             if (str != null && string.Compare(str, "true", StringComparison.OrdinalIgnoreCase ) == 0)
819             {
820                 m_noRestriction = true;
821                 return;
822             }
823 
824             m_noRestriction = false;
825 
826             SecurityElement et = securityElement.SearchForChildByTag("ConnectAccess");
827             string uriPattern;
828 
829             if (et != null) {
830 
831                 foreach(SecurityElement uriElem in et.Children) {
832                     //NOTE: Any stuff coming from XML is treated as URI PATTERN!
833                     if (uriElem.Tag.Equals("URI")) {
834                         try {
835                             uriPattern = uriElem.Attribute("uri");
836                         }
837                         catch {
838                             uriPattern = null;
839                         }
840                         if (uriPattern == null) {
841                             throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val_in_element), "ConnectAccess");
842                         }
843                         if (uriPattern == MatchAll)
844                         {
845                             m_UnrestrictedConnect = true;
846                             m_connectList = new ArrayList();
847                             break;
848                         }
849                         else
850                         {
851                             AddAsPattern(NetworkAccess.Connect, new DelayedRegex(uriPattern));
852                         }
853                     }
854                     else {
855                         // improper tag found, just ignore
856                     }
857                 }
858             }
859 
860             et = securityElement.SearchForChildByTag("AcceptAccess");
861             if (et != null) {
862 
863                 foreach(SecurityElement uriElem in et.Children) {
864                     //NOTE: Any stuff coming from XML is treated as URI PATTERN!
865                     if (uriElem.Tag.Equals("URI")) {
866                         try {
867                             uriPattern = uriElem.Attribute("uri");
868                         }
869                         catch {
870                             uriPattern = null;
871                         }
872                         if (uriPattern == null) {
873                             throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val_in_element), "AcceptAccess");
874                         }
875                         if (uriPattern == MatchAll)
876                         {
877                             m_UnrestrictedAccept = true;
878                             m_acceptList = new ArrayList();
879                             break;
880                         }
881                         else
882                         {
883                             AddAsPattern(NetworkAccess.Accept, new DelayedRegex(uriPattern));
884                         }
885                     }
886                     else {
887                         // improper tag found, just ignore
888                     }
889                 }
890             }
891         }
892 
893         /// <devdoc>
894         ///    <para>[To be supplied.]</para>
895         /// </devdoc>
ToXml()896         public override SecurityElement ToXml() {
897 
898             SecurityElement securityElement = new SecurityElement("IPermission");
899 
900             securityElement.AddAttribute( "class", this.GetType().FullName + ", " + this.GetType().Module.Assembly.FullName.Replace( '\"', '\'' ) );
901             securityElement.AddAttribute( "version", "1" );
902 
903             if (!IsUnrestricted()) {
904                 String tempStr=null;
905 
906                 if (m_UnrestrictedConnect || m_connectList.Count > 0)
907                 {
908                     SecurityElement connectElement = new SecurityElement( "ConnectAccess" );
909 
910                     if (m_UnrestrictedConnect)
911                     {
912                         SecurityElement uripattern = new SecurityElement("URI");
913                         uripattern.AddAttribute("uri", SecurityElement.Escape(MatchAll));
914                         connectElement.AddChild(uripattern);
915                     }
916                     else
917                     {
918                         //NOTE All strings going to XML will become URI PATTERNS i.e. escaped to Regex
919                         foreach(object obj in m_connectList) {
920                             Uri uri = obj as Uri;
921                             if(uri != null)
922                                 tempStr=Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped));
923                             else
924                                 tempStr=obj.ToString();
925 
926                             if (obj is string)
927                                 tempStr = Regex.Escape(tempStr);
928 
929                             SecurityElement uripattern = new SecurityElement("URI");
930                             uripattern.AddAttribute("uri", SecurityElement.Escape(tempStr));
931                             connectElement.AddChild(uripattern);
932                         }
933                     }
934 
935                     securityElement.AddChild( connectElement );
936                 }
937 
938                 if (m_UnrestrictedAccept || m_acceptList.Count > 0)
939                 {
940                     SecurityElement acceptElement = new SecurityElement("AcceptAccess");
941 
942                     if (m_UnrestrictedAccept)
943                     {
944                         SecurityElement uripattern = new SecurityElement("URI");
945                         uripattern.AddAttribute("uri", SecurityElement.Escape(MatchAll));
946                         acceptElement.AddChild(uripattern);
947                     }
948                     else
949                     {
950                         //NOTE All strings going to XML will become URI PATTERNS i.e. escaped to Regex
951                         foreach(object obj in m_acceptList) {
952                             Uri  uri = obj as Uri;
953                             if(uri != null)
954                                 tempStr=Regex.Escape(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped));
955                             else
956                                 tempStr=obj.ToString();
957 
958                             if (obj is string)
959                                 tempStr = Regex.Escape(tempStr);
960 
961                             SecurityElement uripattern = new SecurityElement("URI");
962                             uripattern.AddAttribute("uri", SecurityElement.Escape(tempStr));
963                             acceptElement.AddChild(uripattern);
964                         }
965                     }
966 
967                     securityElement.AddChild( acceptElement );
968                 }
969             }
970             else {
971                 securityElement.AddAttribute( "Unrestricted", "true" );
972             }
973             return securityElement;
974         }
975 
976         // Verifies a single Uri against a set of regular expressions
isMatchedURI(object uriToCheck, ArrayList uriPatternList)977         private static bool isMatchedURI(object uriToCheck, ArrayList uriPatternList) {
978 
979             string stringUri = uriToCheck as string;
980 
981             foreach(object uriPattern in uriPatternList) {
982                 DelayedRegex R = uriPattern as DelayedRegex;
983 
984                 //perform case insensitive comparison of final URIs or strings, a Uri is never equal compares a string (strings are invalid Uris)
985                 if(R == null) {
986                     if (uriToCheck.GetType() == uriPattern.GetType())
987                     {
988                         if (stringUri != null && string.Compare(stringUri, (string)uriPattern, StringComparison.OrdinalIgnoreCase ) == 0) {
989                             return true;
990                         }
991                         else if(stringUri == null && uriToCheck.Equals(uriPattern)) {
992                             return true;
993                         }
994                     }
995                     continue;
996                 }
997 
998                 //Otherwise trying match final URI against given Regex pattern
999                 string s = stringUri != null? stringUri: ((Uri)uriToCheck).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped);
1000                 Match M = R.AsRegex.Match(s);
1001                 if ((M != null)                             // Found match for the regular expression?
1002                     && (M.Index == 0)                       // ... which starts at the begining
1003                     && (M.Length == s.Length)) {            // ... and the whole string matched
1004                     return true;
1005                 }
1006 
1007                 if (stringUri != null)
1008                     continue;
1009                 //
1010                 // check if the URI was presented in non-canonical form
1011                 //
1012                 s = ((Uri)uriToCheck).GetComponents(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped);
1013                 M = R.AsRegex.Match(s);
1014                 if ((M != null)                             // Found match for the regular expression?
1015                     && (M.Index == 0)                       // ... which starts at the begining
1016                     && (M.Length == s.Length)) {   // ... and the whole string matched
1017                     return true;
1018                 }
1019             }
1020             return false;
1021         }
1022 
1023         // We should keep the result as compact as possible since otherwise even
1024         // simple scenarios in Policy Wizard won;t work due to repeated Union/Intersect calls
1025         // The issue comes from the "hard" Regex.IsSubsetOf(Regex) problem.
intersectList(ArrayList A, ArrayList B, ArrayList result)1026         private static void intersectList(ArrayList A, ArrayList B, ArrayList result) {
1027             bool[]  aDone = new bool[A.Count];
1028             bool[]  bDone = new bool[B.Count];
1029             int     ia=0, ib;
1030 
1031             // The optimization is done according to the following truth
1032             // (A|B|C) intersect (B|C|E|D)) == B|C|(A inter E)|(A inter D)
1033             //
1034             // We also check on any duplicates in the result
1035 
1036             // Round 1st
1037             // Getting rid of same permissons in the input arrays (assuming X /\ X = X)
1038             foreach (object a in  A) {
1039                 ib = 0;
1040                 foreach (object b in  B) {
1041 
1042                     // check to see if b is in the result already
1043                     if (!bDone[ib]) {
1044 
1045                         //if both are regexes or both are Uris or both are strings
1046                         if (a.GetType() == b.GetType())
1047                         {
1048                             if (a is Uri)
1049                             {
1050                                 // both are uris
1051                                 if (a.Equals(b))
1052                                 {
1053                                     result.Add(a);
1054                                     aDone[ia]=bDone[ib]=true;
1055                                     //since permissions are ORed we can break and go to the next A
1056                                     break;
1057                                 }
1058                             }
1059                             else
1060                             {
1061                                 // regexes and strings uses ToString() output
1062                                 if (string.Compare(a.ToString(), b.ToString(), StringComparison.OrdinalIgnoreCase ) == 0)
1063                                 {
1064                                     result.Add(a);
1065                                     aDone[ia]=bDone[ib]=true;
1066                                     //since permissions are ORed we can break and go to the next A
1067                                     break;
1068                                 }
1069                             }
1070                         }
1071                     }
1072                     ++ib;
1073                 } //foreach b in B
1074                 ++ia;
1075             } //foreach a in A
1076 
1077             ia = 0;
1078             // Round second
1079             // Grab only intersections of objects not found in both A and B
1080             foreach (object a in  A) {
1081 
1082                 if (!aDone[ia]) {
1083                     ib = 0;
1084                     foreach(object b in B) {
1085 
1086                         if (!bDone[ib]) {
1087                             bool resultUri;
1088                             object intesection = intersectPair(a, b, out resultUri);
1089 
1090                             if (intesection != null) {
1091                                 bool found = false;
1092                                 // check to see if we already have the same result
1093                                 foreach (object obj in result) {
1094                                     if (resultUri == (obj is Uri))
1095                                     {
1096                                         if(resultUri
1097                                            ? intesection.Equals(obj)
1098                                            : string.Compare(obj.ToString(), intesection.ToString(), StringComparison.OrdinalIgnoreCase ) == 0)
1099                                         {
1100                                             found = true;
1101                                             break;
1102                                         }
1103                                     }
1104                                 }
1105 
1106                                 if (!found) {
1107                                     result.Add(intesection);
1108                                 }
1109                             }
1110                         }
1111                         ++ib;
1112                     }
1113                 }
1114                 ++ia;
1115             }
1116         }
1117 
intersectPair(object L, object R, out bool isUri)1118         private static object intersectPair(object L, object R, out bool isUri) {
1119 
1120             //VERY OLD OPTION:  return new Regex("(?=(" + ((Regex)X[i]).ToString()+ "))(" + ((Regex)Y[j]).ToString() + ")","i");
1121             //STILL OLD OPTION: return new Regex("(?=.*?(" + L.ToString() + "))" + "(?=.*?(" + R.ToString() + "))");
1122             // check RegexSpec.doc
1123             //CURRENT OPTION:   return new Regex("(?=(" + L.ToString() + "))(" + R.ToString() + ")", RegexOptions.IgnoreCase );
1124             isUri = false;
1125             DelayedRegex L_Pattern =L as DelayedRegex;
1126             DelayedRegex R_Pattern =R as DelayedRegex;
1127 
1128             if(L_Pattern != null && R_Pattern != null)  {       //both are Regex
1129                 return new DelayedRegex("(?=(" + L_Pattern.ToString() + "))(" + R_Pattern.ToString() + ")");
1130             }
1131             else if(L_Pattern != null && R_Pattern == null) {   //only L is a Regex
1132                     isUri = R is Uri;
1133                     string uriString = isUri? ((Uri)R).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped): R.ToString();
1134 
1135                     Match M = L_Pattern.AsRegex.Match(uriString);
1136                     if ((M != null)                             // Found match for the regular expression?
1137                         && (M.Index == 0)                       // ... which starts at the begining
1138                         && (M.Length == uriString.Length)) { // ... and the whole string matched
1139                         return R;
1140                     }
1141                     return null;
1142             }
1143             else if(L_Pattern == null && R_Pattern != null) {   //only R is a Regex
1144                     isUri = L is Uri;
1145                     string uriString = isUri? ((Uri)L).GetComponents(UriComponents.HttpRequestUrl, UriFormat.UriEscaped):  L.ToString();
1146                     Match M = R_Pattern.AsRegex.Match(uriString);
1147                     if ((M != null)                             // Found match for the regular expression?
1148                         && (M.Index == 0)                       // ... which starts at the begining
1149                         && (M.Length == uriString.Length)) { // ... and the whole string matched
1150                         return L;
1151                     }
1152                     return null;
1153            }
1154            //both are Uris or strings
1155            isUri = L is Uri;
1156            if (isUri)
1157                return L.Equals(R)? L : null;
1158            else
1159                return string.Compare(L.ToString(), R.ToString(), StringComparison.OrdinalIgnoreCase ) == 0? L : null;
1160         }
1161     } // class WebPermission
1162 } // namespace System.Net
1163