Socket permission stuff, not yet used by Socket itself.
[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 \r
8 using System;\r
9 using System.Collections;\r
10 using System.Security;\r
11 using System.Security.Permissions;\r
12 \r
13 namespace System.Net\r
14 {\r
15         [Serializable]\r
16         public class SocketPermission : CodeAccessPermission, IUnrestrictedPermission\r
17         {\r
18                 // Fields\r
19                 ArrayList m_acceptList = new ArrayList ();\r
20                 ArrayList m_connectList = new ArrayList ();\r
21                 bool m_noRestriction;\r
22                 \r
23                 // Constructors\r
24                 public SocketPermission (PermissionState state) : base () \r
25                 {                                               \r
26                         m_noRestriction = (state == PermissionState.Unrestricted);\r
27                 }\r
28                 \r
29                 public SocketPermission (NetworkAccess access, TransportType transport, \r
30                                          string hostName, int portNumber) : base () \r
31                 {\r
32                         m_noRestriction = false;\r
33                         AddPermission (access, transport, hostName, portNumber);\r
34                 }       \r
35                 \r
36                 // Fields\r
37                 public const int AllPorts = -1;\r
38                 \r
39                 // Properties\r
40 \r
41                 public IEnumerator AcceptList {\r
42                         get { return m_acceptList.GetEnumerator (); }\r
43                 }\r
44 \r
45                 public IEnumerator ConnectList {\r
46                         get { return m_connectList.GetEnumerator (); }\r
47                 }\r
48                 \r
49                 // Methods\r
50                 \r
51                 public void AddPermission (NetworkAccess access, TransportType transport,\r
52                                            string hostName, int portNumber)\r
53                 {\r
54                         if (m_noRestriction)\r
55                                 return;\r
56                                 \r
57                         EndpointPermission permission = new EndpointPermission (hostName, portNumber, transport);\r
58 \r
59                         if (access == NetworkAccess.Accept)\r
60                                 m_acceptList.Add (permission);\r
61                         else\r
62                                 m_connectList.Add (permission);\r
63                 }               \r
64                 \r
65                 public override IPermission Copy ()\r
66                 {\r
67                         SocketPermission permission;\r
68 \r
69                         permission = new SocketPermission (m_noRestriction ? \r
70                                                 PermissionState.Unrestricted : \r
71                                                 PermissionState.None);\r
72 \r
73                         // as EndpointPermission's are immutable it's safe to do a shallow copy.                                                \r
74                         permission.m_connectList = (ArrayList) this.m_connectList.Clone ();\r
75                         permission.m_acceptList = (ArrayList) this.m_acceptList.Clone ();\r
76 \r
77                         return permission;              \r
78                 }\r
79                 \r
80                 public override IPermission Intersect (IPermission target)\r
81                 {\r
82                         if (target == null) \r
83                                 return null;\r
84                                 \r
85                         SocketPermission perm = target as SocketPermission;\r
86                         if (perm == null) \r
87                                 throw new ArgumentException ("Argument not of type SocketPermission");\r
88                         \r
89                         if (m_noRestriction) \r
90                                 return IntersectEmpty (perm) ? null : perm.Copy ();\r
91                                 \r
92                         if (perm.m_noRestriction)\r
93                                 return IntersectEmpty (this) ? null : this.Copy ();\r
94                                 \r
95                         SocketPermission newperm = new SocketPermission (PermissionState.None);\r
96                         Intersect (this.m_connectList, perm.m_connectList, newperm.m_connectList);\r
97                         Intersect (this.m_acceptList, perm.m_acceptList, newperm.m_acceptList);\r
98                         return IntersectEmpty (newperm) ? null : newperm;                       \r
99                 }\r
100                 \r
101                 private bool IntersectEmpty (SocketPermission permission)               \r
102                 {\r
103                         return !permission.m_noRestriction && \r
104                                (permission.m_connectList.Count == 0) &&\r
105                                (permission.m_acceptList.Count == 0);\r
106                 }\r
107                 \r
108                 private void Intersect (ArrayList list1, ArrayList list2, ArrayList result)\r
109                 {\r
110                         foreach (EndpointPermission perm1 in list1) {\r
111                                 foreach (EndpointPermission perm2 in list2) {\r
112                                         EndpointPermission perm = perm1.Intersect (perm2);\r
113                                         if (perm != null) {\r
114                                                 // instead of the below it's also okay to simply do:\r
115                                                 //     result.Add (perm);\r
116                                                 // below is only done to avoid double entries                                           \r
117                                                 bool replaced = false;\r
118                                                 for (int i = 0; i < result.Count; i++) {\r
119                                                         EndpointPermission res = (EndpointPermission) result [i];\r
120                                                         EndpointPermission resperm = perm.Intersect (res);\r
121                                                         if (resperm != null) {\r
122                                                                 result [i] = resperm;\r
123                                                                 replaced = true;\r
124                                                                 break;\r
125                                                         }\r
126                                                 }\r
127                                                 if (!replaced) \r
128                                                         result.Add (perm);\r
129                                         }\r
130                                 }\r
131                         }\r
132                 }\r
133                 \r
134                 public override bool IsSubsetOf (IPermission target) \r
135                 {\r
136                         if (target == null)\r
137                                 return (!m_noRestriction && m_connectList.Count == 0 && m_acceptList.Count ==    0);\r
138                         \r
139                         SocketPermission perm = target as SocketPermission;\r
140 \r
141                         if (perm == null) \r
142                                 throw new ArgumentException ("Parameter target must be of type SocketPermission");\r
143                         \r
144                         if (perm.m_noRestriction) \r
145                                 return true;\r
146 \r
147                         if (this.m_noRestriction)\r
148                                 return false;\r
149 \r
150                         if (this.m_acceptList.Count == 0 && this.m_connectList.Count == 0)\r
151                                 return true;\r
152 \r
153                         if (perm.m_acceptList.Count == 0 && perm.m_connectList.Count == 0)\r
154                                 return false;\r
155 \r
156                         return IsSubsetOf (this.m_connectList, perm.m_connectList)\r
157                             && IsSubsetOf (this.m_acceptList, perm.m_acceptList);\r
158                 }\r
159 \r
160                 private bool IsSubsetOf (ArrayList list1, ArrayList list2)\r
161                 {\r
162                         foreach (EndpointPermission perm1 in list1) {\r
163                                 bool issubset = false;\r
164                                 foreach (EndpointPermission perm2 in list2) \r
165                                         if (perm1.IsSubsetOf (perm2)) {\r
166                                                 issubset = true;\r
167                                                 break;\r
168                                         }\r
169                                 if (!issubset) \r
170                                         return false;\r
171                         }\r
172                         return true;\r
173                 }\r
174                 \r
175                 public bool IsUnrestricted () \r
176                 {\r
177                         return m_noRestriction;\r
178                 }\r
179 \r
180                 /*\r
181                 \r
182                 SocketPermission s = new SocketPermission (NetworkAccess.Connect, TransportType.Tcp, "www.google.com", 80);\r
183                 s.AddPermission (NetworkAccess.Accept, TransportType.All, "localhost", 8080);\r
184                 s.AddPermission (NetworkAccess.Accept, TransportType.All, "localhost", SocketPermission.AllPorts);\r
185                 // s = new SocketPermission (PermissionState.None);\r
186                 SecurityElement sec = s.ToXml ();       \r
187                 Console.WriteLine (sec.ToString ());\r
188 \r
189                 This is sample xml output:\r
190 \r
191                 <IPermission class="System.Net.SocketPermission, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"\r
192                              version="1">\r
193                    <ConnectAccess>\r
194                       <ENDPOINT host="www.google.com"\r
195                                 transport="Tcp"\r
196                                 port="80"/>\r
197                    </ConnectAccess>\r
198                    <AcceptAccess>\r
199                       <ENDPOINT host="localhost"\r
200                                 transport="All"\r
201                                 port="8080"/>\r
202                       <ENDPOINT host="localhost"\r
203                                 transport="All"\r
204                                 port="All"/>\r
205                    </AcceptAccess>\r
206                 </IPermission>\r
207 \r
208 \r
209 \r
210                 This is a sample unrestricted socketpermission, no matter how many permissions you add:                 \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                              Unrestricted="true"/>\r
215 \r
216 \r
217                 This is a sample constructed restricted socketpermission with no permissions added:\r
218 \r
219                 <IPermission class="System.Net.SocketPermission, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"\r
220                              version="1"/>\r
221                 */\r
222                 public override SecurityElement ToXml ()\r
223                 {\r
224              \r
225                         SecurityElement root = new SecurityElement ("IPermission");\r
226 \r
227                         root.AddAttribute ("class", this.GetType ().FullName + ", " + \r
228                                                     "System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");\r
229 \r
230 /*                      \r
231 GetType ().Module doesn't work yet with Mono.. (2002-04-27)\r
232 We need to do it as below though, because this class can be extended\r
233 \r
234                         root.AddAttribute ("class", this.GetType ().FullName + ", " + \r
235                                                     this.GetType ().Module.Assembly.FullName);\r
236 */                                                  \r
237                         root.AddAttribute ("version", "1");\r
238                         if (m_noRestriction) {\r
239                                 root.AddAttribute ("Unrestricted", "true");                             \r
240                                 return root;\r
241                         }                               \r
242                                 \r
243                         if (this.m_connectList.Count > 0)\r
244                                 ToXml (root, "ConnectAccess", m_connectList.GetEnumerator ());\r
245                         \r
246                         if (this.m_acceptList.Count > 0) \r
247                                 ToXml (root, "AcceptAccess", m_acceptList.GetEnumerator ());                    \r
248                         \r
249                         return root;\r
250                 }\r
251                 \r
252                 private void ToXml (SecurityElement root, string childName, IEnumerator enumerator)\r
253                 {\r
254                         SecurityElement child = new SecurityElement (childName);\r
255                         while (enumerator.MoveNext ()) {\r
256                                 EndpointPermission perm = enumerator.Current as EndpointPermission;\r
257                                 SecurityElement grandchild = new SecurityElement ("ENDPOINT");\r
258                                 grandchild.AddAttribute ("host", perm.Hostname);\r
259                                 grandchild.AddAttribute ("transport", perm.Transport.ToString ());\r
260                                 grandchild.AddAttribute ("port", \r
261                                                 perm.Port == AllPorts \r
262                                                 ? "All" \r
263                                                 : ((Int32) perm.Port).ToString ());\r
264                                 child.AddChild (grandchild);\r
265                         }\r
266                         root.AddChild (child);\r
267                 }\r
268                 \r
269                 public override void FromXml (SecurityElement securityElement)\r
270                 {\r
271                         if (securityElement == null)\r
272                                 throw new ArgumentNullException ("securityElement");\r
273                                 \r
274                         // LAMESPEC: it says to throw an ArgumentNullException in this case                             \r
275                         if (securityElement.Tag != "IPermission")\r
276                                 throw new ArgumentException ("securityElement");\r
277                                 \r
278                         string classStr = securityElement.Attribute ("class");\r
279                         if (classStr == null || !classStr.StartsWith (this.GetType ().FullName + ","))\r
280                                 throw new ArgumentException ("securityElement");\r
281                                 \r
282                         string unrestricted = securityElement.Attribute ("Unrestricted");\r
283                         if (unrestricted != null) {\r
284                                 this.m_noRestriction = (String.Compare (unrestricted, "true", true) == 0);\r
285                                 if (this.m_noRestriction)\r
286                                         return;\r
287                         }\r
288                         \r
289                         this.m_noRestriction = false;\r
290                         this.m_connectList = new ArrayList ();\r
291                         this.m_acceptList = new ArrayList ();\r
292                         \r
293                         ArrayList children = securityElement.Children;\r
294                         foreach (SecurityElement child in children) {\r
295                                 if (child.Tag == "ConnectAccess") \r
296                                         FromXml (child.Children, NetworkAccess.Connect);\r
297                                 else if (child.Tag == "AcceptAccess")\r
298                                         FromXml (child.Children, NetworkAccess.Accept);\r
299                         }\r
300                 }               \r
301                 \r
302                 private void FromXml (ArrayList endpoints, NetworkAccess access)\r
303                 {\r
304                         foreach (SecurityElement endpoint in endpoints) {\r
305                                 if (endpoint.Tag != "ENDPOINT")\r
306                                         continue;\r
307                                 string hostname = endpoint.Attribute ("host");\r
308                                 TransportType transport = \r
309                                         (TransportType) Enum.Parse (typeof (TransportType), \r
310                                                                     endpoint.Attribute ("transport"), \r
311                                                                     true);\r
312                                 string p = endpoint.Attribute ("port");\r
313                                 int port = 0;\r
314                                 if (p == "All") \r
315                                         port = SocketPermission.AllPorts;\r
316                                 else\r
317                                         port = Int32.Parse (p);\r
318 \r
319                                 AddPermission (access, transport, hostname, port);\r
320                         }\r
321                 }\r
322                 \r
323                 public override IPermission Union (IPermission target) \r
324                 {\r
325                         // LAMESPEC: according to spec we should throw an \r
326                         // exception when target is null. We'll follow the\r
327                         // behaviour of MS.Net instead of the spec, also\r
328                         // because it matches the Intersect behaviour.\r
329                         if (target == null)\r
330                                 return null;\r
331                                 // throw new ArgumentNullException ("target");\r
332                                 \r
333                         SocketPermission perm = target as SocketPermission;\r
334                         if (perm == null)\r
335                                 throw new ArgumentException ("Argument not of type SocketPermission");\r
336                         \r
337                         if (this.m_noRestriction || perm.m_noRestriction) \r
338                                 return new SocketPermission (PermissionState.Unrestricted);\r
339                                 \r
340                         SocketPermission copy = (SocketPermission) perm.Copy ();\r
341                         copy.m_acceptList.InsertRange (copy.m_acceptList.Count, this.m_acceptList);\r
342                         copy.m_connectList.InsertRange (copy.m_connectList.Count, this.m_connectList);                          \r
343                         \r
344                         return copy;\r
345                 }\r
346 \r
347         }\r
348 }\r