This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / System / System.Net / SocketPermission.cs
1 //\r
2 // System.Net.SocketPermission.cs\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 \r
29 using System;\r
30 using System.Collections;\r
31 using System.Security;\r
32 using System.Security.Permissions;\r
33 \r
34 namespace System.Net\r
35 {\r
36         [Serializable]\r
37         public sealed class SocketPermission : CodeAccessPermission, IUnrestrictedPermission\r
38         {\r
39                 // Fields\r
40                 ArrayList m_acceptList = new ArrayList ();\r
41                 ArrayList m_connectList = new ArrayList ();\r
42                 bool m_noRestriction;\r
43                 \r
44                 // Constructors\r
45                 public SocketPermission (PermissionState state) : base () \r
46                 {                                               \r
47                         m_noRestriction = (state == PermissionState.Unrestricted);\r
48                 }\r
49                 \r
50                 public SocketPermission (NetworkAccess access, TransportType transport, \r
51                                          string hostName, int portNumber) : base () \r
52                 {\r
53                         m_noRestriction = false;\r
54                         AddPermission (access, transport, hostName, portNumber);\r
55                 }       \r
56                 \r
57                 // Fields\r
58                 public const int AllPorts = -1;\r
59                 \r
60                 // Properties\r
61 \r
62                 public IEnumerator AcceptList {\r
63                         get { return m_acceptList.GetEnumerator (); }\r
64                 }\r
65 \r
66                 public IEnumerator ConnectList {\r
67                         get { return m_connectList.GetEnumerator (); }\r
68                 }\r
69                 \r
70                 // Methods\r
71                 \r
72                 public void AddPermission (NetworkAccess access, TransportType transport,\r
73                                            string hostName, int portNumber)\r
74                 {\r
75                         if (m_noRestriction)\r
76                                 return;\r
77                                 \r
78                         EndpointPermission permission = new EndpointPermission (hostName, portNumber, transport);\r
79 \r
80                         if (access == NetworkAccess.Accept)\r
81                                 m_acceptList.Add (permission);\r
82                         else\r
83                                 m_connectList.Add (permission);\r
84                 }               \r
85                 \r
86                 public override IPermission Copy ()\r
87                 {\r
88                         SocketPermission permission;\r
89 \r
90                         permission = new SocketPermission (m_noRestriction ? \r
91                                                 PermissionState.Unrestricted : \r
92                                                 PermissionState.None);\r
93 \r
94                         // as EndpointPermission's are immutable it's safe to do a shallow copy.                                                \r
95                         permission.m_connectList = (ArrayList) this.m_connectList.Clone ();\r
96                         permission.m_acceptList = (ArrayList) this.m_acceptList.Clone ();\r
97 \r
98                         return permission;              \r
99                 }\r
100                 \r
101                 public override IPermission Intersect (IPermission target)\r
102                 {\r
103                         if (target == null) \r
104                                 return null;\r
105                                 \r
106                         SocketPermission perm = target as SocketPermission;\r
107                         if (perm == null) \r
108                                 throw new ArgumentException ("Argument not of type SocketPermission");\r
109                         \r
110                         if (m_noRestriction) \r
111                                 return IntersectEmpty (perm) ? null : perm.Copy ();\r
112                                 \r
113                         if (perm.m_noRestriction)\r
114                                 return IntersectEmpty (this) ? null : this.Copy ();\r
115                                 \r
116                         SocketPermission newperm = new SocketPermission (PermissionState.None);\r
117                         Intersect (this.m_connectList, perm.m_connectList, newperm.m_connectList);\r
118                         Intersect (this.m_acceptList, perm.m_acceptList, newperm.m_acceptList);\r
119                         return IntersectEmpty (newperm) ? null : newperm;                       \r
120                 }\r
121                 \r
122                 private bool IntersectEmpty (SocketPermission permission)               \r
123                 {\r
124                         return !permission.m_noRestriction && \r
125                                (permission.m_connectList.Count == 0) &&\r
126                                (permission.m_acceptList.Count == 0);\r
127                 }\r
128                 \r
129                 private void Intersect (ArrayList list1, ArrayList list2, ArrayList result)\r
130                 {\r
131                         foreach (EndpointPermission perm1 in list1) {\r
132                                 foreach (EndpointPermission perm2 in list2) {\r
133                                         EndpointPermission perm = perm1.Intersect (perm2);\r
134                                         if (perm != null) {\r
135                                                 // instead of the below it's also okay to simply do:\r
136                                                 //     result.Add (perm);\r
137                                                 // below is only done to avoid double entries                                           \r
138                                                 bool replaced = false;\r
139                                                 for (int i = 0; i < result.Count; i++) {\r
140                                                         EndpointPermission res = (EndpointPermission) result [i];\r
141                                                         EndpointPermission resperm = perm.Intersect (res);\r
142                                                         if (resperm != null) {\r
143                                                                 result [i] = resperm;\r
144                                                                 replaced = true;\r
145                                                                 break;\r
146                                                         }\r
147                                                 }\r
148                                                 if (!replaced) \r
149                                                         result.Add (perm);\r
150                                         }\r
151                                 }\r
152                         }\r
153                 }\r
154                 \r
155                 public override bool IsSubsetOf (IPermission target) \r
156                 {\r
157                         if (target == null)\r
158                                 return (!m_noRestriction && m_connectList.Count == 0 && m_acceptList.Count ==    0);\r
159                         \r
160                         SocketPermission perm = target as SocketPermission;\r
161 \r
162                         if (perm == null) \r
163                                 throw new ArgumentException ("Parameter target must be of type SocketPermission");\r
164                         \r
165                         if (perm.m_noRestriction) \r
166                                 return true;\r
167 \r
168                         if (this.m_noRestriction)\r
169                                 return false;\r
170 \r
171                         if (this.m_acceptList.Count == 0 && this.m_connectList.Count == 0)\r
172                                 return true;\r
173 \r
174                         if (perm.m_acceptList.Count == 0 && perm.m_connectList.Count == 0)\r
175                                 return false;\r
176 \r
177                         return IsSubsetOf (this.m_connectList, perm.m_connectList)\r
178                             && IsSubsetOf (this.m_acceptList, perm.m_acceptList);\r
179                 }\r
180 \r
181                 private bool IsSubsetOf (ArrayList list1, ArrayList list2)\r
182                 {\r
183                         foreach (EndpointPermission perm1 in list1) {\r
184                                 bool issubset = false;\r
185                                 foreach (EndpointPermission perm2 in list2) \r
186                                         if (perm1.IsSubsetOf (perm2)) {\r
187                                                 issubset = true;\r
188                                                 break;\r
189                                         }\r
190                                 if (!issubset) \r
191                                         return false;\r
192                         }\r
193                         return true;\r
194                 }\r
195                 \r
196                 public bool IsUnrestricted () \r
197                 {\r
198                         return m_noRestriction;\r
199                 }\r
200 \r
201                 /*\r
202                 \r
203                 SocketPermission s = new SocketPermission (NetworkAccess.Connect, TransportType.Tcp, "www.google.com", 80);\r
204                 s.AddPermission (NetworkAccess.Accept, TransportType.All, "localhost", 8080);\r
205                 s.AddPermission (NetworkAccess.Accept, TransportType.All, "localhost", SocketPermission.AllPorts);\r
206                 // s = new SocketPermission (PermissionState.None);\r
207                 SecurityElement sec = s.ToXml ();       \r
208                 Console.WriteLine (sec.ToString ());\r
209 \r
210                 This is sample xml output:\r
211 \r
212                 <IPermission class="System.Net.SocketPermission, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"\r
213                              version="1">\r
214                    <ConnectAccess>\r
215                       <ENDPOINT host="www.google.com"\r
216                                 transport="Tcp"\r
217                                 port="80"/>\r
218                    </ConnectAccess>\r
219                    <AcceptAccess>\r
220                       <ENDPOINT host="localhost"\r
221                                 transport="All"\r
222                                 port="8080"/>\r
223                       <ENDPOINT host="localhost"\r
224                                 transport="All"\r
225                                 port="All"/>\r
226                    </AcceptAccess>\r
227                 </IPermission>\r
228 \r
229 \r
230 \r
231                 This is a sample unrestricted socketpermission, no matter how many permissions you add:                 \r
232 \r
233                 <IPermission class="System.Net.SocketPermission, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"\r
234                              version="1"\r
235                              Unrestricted="true"/>\r
236 \r
237 \r
238                 This is a sample constructed restricted socketpermission with no permissions added:\r
239 \r
240                 <IPermission class="System.Net.SocketPermission, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"\r
241                              version="1"/>\r
242                 */\r
243                 public override SecurityElement ToXml ()\r
244                 {\r
245              \r
246                         SecurityElement root = new SecurityElement ("IPermission");\r
247 \r
248                         root.AddAttribute ("class", this.GetType ().AssemblyQualifiedName);\r
249                         root.AddAttribute ("version", "1");\r
250                         if (m_noRestriction) {\r
251                                 root.AddAttribute ("Unrestricted", "true");                             \r
252                                 return root;\r
253                         }                               \r
254                                 \r
255                         if (this.m_connectList.Count > 0)\r
256                                 ToXml (root, "ConnectAccess", m_connectList.GetEnumerator ());\r
257                         \r
258                         if (this.m_acceptList.Count > 0) \r
259                                 ToXml (root, "AcceptAccess", m_acceptList.GetEnumerator ());                    \r
260                         \r
261                         return root;\r
262                 }\r
263                 \r
264                 private void ToXml (SecurityElement root, string childName, IEnumerator enumerator)\r
265                 {\r
266                         SecurityElement child = new SecurityElement (childName);\r
267                         while (enumerator.MoveNext ()) {\r
268                                 EndpointPermission perm = enumerator.Current as EndpointPermission;\r
269                                 SecurityElement grandchild = new SecurityElement ("ENDPOINT");\r
270                                 grandchild.AddAttribute ("host", perm.Hostname);\r
271                                 grandchild.AddAttribute ("transport", perm.Transport.ToString ());\r
272                                 grandchild.AddAttribute ("port", \r
273                                                 perm.Port == AllPorts \r
274                                                 ? "All" \r
275                                                 : ((Int32) perm.Port).ToString ());\r
276                                 child.AddChild (grandchild);\r
277                         }\r
278                         root.AddChild (child);\r
279                 }\r
280                 \r
281                 public override void FromXml (SecurityElement securityElement)\r
282                 {\r
283                         if (securityElement == null)\r
284                                 throw new ArgumentNullException ("securityElement");\r
285                                 \r
286                         // LAMESPEC: it says to throw an ArgumentNullException in this case                             \r
287                         if (securityElement.Tag != "IPermission")\r
288                                 throw new ArgumentException ("securityElement");\r
289                                 \r
290                         string classStr = securityElement.Attribute ("class");\r
291                         if (classStr == null || !classStr.StartsWith (this.GetType ().FullName + ","))\r
292                                 throw new ArgumentException ("securityElement");\r
293                                 \r
294                         string unrestricted = securityElement.Attribute ("Unrestricted");\r
295                         if (unrestricted != null) {\r
296                                 this.m_noRestriction = (String.Compare (unrestricted, "true", true) == 0);\r
297                                 if (this.m_noRestriction)\r
298                                         return;\r
299                         }\r
300                         \r
301                         this.m_noRestriction = false;\r
302                         this.m_connectList = new ArrayList ();\r
303                         this.m_acceptList = new ArrayList ();\r
304                         \r
305                         ArrayList children = securityElement.Children;\r
306                         foreach (SecurityElement child in children) {\r
307                                 if (child.Tag == "ConnectAccess") \r
308                                         FromXml (child.Children, NetworkAccess.Connect);\r
309                                 else if (child.Tag == "AcceptAccess")\r
310                                         FromXml (child.Children, NetworkAccess.Accept);\r
311                         }\r
312                 }               \r
313                 \r
314                 private void FromXml (ArrayList endpoints, NetworkAccess access)\r
315                 {\r
316                         foreach (SecurityElement endpoint in endpoints) {\r
317                                 if (endpoint.Tag != "ENDPOINT")\r
318                                         continue;\r
319                                 string hostname = endpoint.Attribute ("host");\r
320                                 TransportType transport = \r
321                                         (TransportType) Enum.Parse (typeof (TransportType), \r
322                                                                     endpoint.Attribute ("transport"), \r
323                                                                     true);\r
324                                 string p = endpoint.Attribute ("port");\r
325                                 int port = 0;\r
326                                 if (p == "All") \r
327                                         port = SocketPermission.AllPorts;\r
328                                 else\r
329                                         port = Int32.Parse (p);\r
330 \r
331                                 AddPermission (access, transport, hostname, port);\r
332                         }\r
333                 }\r
334                 \r
335                 public override IPermission Union (IPermission target) \r
336                 {\r
337                         // LAMESPEC: according to spec we should throw an \r
338                         // exception when target is null. We'll follow the\r
339                         // behaviour of MS.Net instead of the spec, also\r
340                         // because it matches the Intersect behaviour.\r
341                         if (target == null)\r
342                                 return null;\r
343                                 // throw new ArgumentNullException ("target");\r
344                                 \r
345                         SocketPermission perm = target as SocketPermission;\r
346                         if (perm == null)\r
347                                 throw new ArgumentException ("Argument not of type SocketPermission");\r
348                         \r
349                         if (this.m_noRestriction || perm.m_noRestriction) \r
350                                 return new SocketPermission (PermissionState.Unrestricted);\r
351                                 \r
352                         SocketPermission copy = (SocketPermission) perm.Copy ();\r
353                         copy.m_acceptList.InsertRange (copy.m_acceptList.Count, this.m_acceptList);\r
354                         copy.m_connectList.InsertRange (copy.m_connectList.Count, this.m_connectList);                          \r
355                         \r
356                         return copy;\r
357                 }\r
358 \r
359         }\r
360 }\r