ResourcePermissionBase.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. //
  2. // System.Security.Permissions.ResourcePermissionBase.cs
  3. //
  4. // Authors:
  5. // Jonathan Pryor ([email protected])
  6. // Sebastien Pouliot <[email protected]>
  7. //
  8. // (C) 2002
  9. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System.Collections;
  31. using System.Globalization;
  32. namespace System.Security.Permissions {
  33. [Serializable]
  34. public abstract class ResourcePermissionBase : CodeAccessPermission, IUnrestrictedPermission {
  35. private const int version = 1;
  36. private ArrayList _list;
  37. private bool _unrestricted;
  38. private Type _type;
  39. private string[] _tags;
  40. protected ResourcePermissionBase ()
  41. {
  42. _list = new ArrayList ();
  43. }
  44. protected ResourcePermissionBase (PermissionState state) : this ()
  45. {
  46. #if NET_2_0
  47. PermissionHelper.CheckPermissionState (state, true);
  48. #else
  49. // there are no validation of the permission state
  50. // but any invalid value results in a restricted set
  51. #endif
  52. _unrestricted = (state == PermissionState.Unrestricted);
  53. }
  54. public const string Any = "*";
  55. public const string Local = ".";
  56. protected Type PermissionAccessType {
  57. get { return _type; }
  58. set {
  59. if (value == null)
  60. throw new ArgumentNullException ("PermissionAccessType");
  61. if (!value.IsEnum)
  62. throw new ArgumentException ("!Enum", "PermissionAccessType");
  63. _type = value;
  64. }
  65. }
  66. protected string[] TagNames {
  67. get { return _tags; }
  68. set {
  69. if (value == null)
  70. throw new ArgumentNullException ("TagNames");
  71. if (value.Length == 0)
  72. throw new ArgumentException ("Length==0", "TagNames");
  73. _tags = value;
  74. }
  75. }
  76. protected void AddPermissionAccess (ResourcePermissionBaseEntry entry)
  77. {
  78. CheckEntry (entry);
  79. if (Exists (entry)) {
  80. string msg = Locale.GetText ("Entry already exists.");
  81. throw new InvalidOperationException (msg);
  82. }
  83. _list.Add (entry);
  84. }
  85. protected void Clear ()
  86. {
  87. _list.Clear ();
  88. }
  89. public override IPermission Copy ()
  90. {
  91. ResourcePermissionBase copy = CreateFromType (this.GetType (), _unrestricted);
  92. if (_tags != null)
  93. copy._tags = (string[]) _tags.Clone ();
  94. copy._type = _type;
  95. // FIXME: shallow or deep copy ?
  96. copy._list.AddRange (_list);
  97. return copy;
  98. }
  99. [MonoTODO ("incomplete - need more test")]
  100. public override void FromXml (SecurityElement securityElement)
  101. {
  102. #if NET_2_0
  103. if (securityElement == null)
  104. throw new ArgumentNullException ("securityElement");
  105. #else
  106. if (securityElement == null)
  107. throw new NullReferenceException ("securityElement");
  108. #endif
  109. CheckSecurityElement (securityElement, "securityElement", version, version);
  110. // Note: we do not (yet) care about the return value
  111. // as we only accept version 1 (min/max values)
  112. _list.Clear ();
  113. _unrestricted = PermissionHelper.IsUnrestricted (securityElement);
  114. if ((securityElement.Children == null) || (securityElement.Children.Count < 1))
  115. return;
  116. string[] names = new string [1];
  117. foreach (SecurityElement child in securityElement.Children) {
  118. // TODO: handle multiple names
  119. names [0] = child.Attribute ("name");
  120. int access = (int) Enum.Parse (PermissionAccessType, child.Attribute ("access"));
  121. ResourcePermissionBaseEntry entry = new ResourcePermissionBaseEntry (access, names);
  122. AddPermissionAccess (entry);
  123. }
  124. }
  125. protected ResourcePermissionBaseEntry[] GetPermissionEntries ()
  126. {
  127. ResourcePermissionBaseEntry[] entries = new ResourcePermissionBaseEntry [_list.Count];
  128. _list.CopyTo (entries, 0);
  129. return entries;
  130. }
  131. public override IPermission Intersect (IPermission target)
  132. {
  133. ResourcePermissionBase rpb = Cast (target);
  134. if (rpb == null)
  135. return null;
  136. bool su = this.IsUnrestricted ();
  137. bool tu = rpb.IsUnrestricted ();
  138. // if one is empty we return null (unless the other one is unrestricted)
  139. if (IsEmpty () && !tu)
  140. return null;
  141. if (rpb.IsEmpty () && !su)
  142. return null;
  143. ResourcePermissionBase result = CreateFromType (this.GetType (), (su && tu));
  144. foreach (ResourcePermissionBaseEntry entry in _list) {
  145. if (tu || rpb.Exists (entry))
  146. result.AddPermissionAccess (entry);
  147. }
  148. foreach (ResourcePermissionBaseEntry entry in rpb._list) {
  149. // don't add twice
  150. if ((su || this.Exists (entry)) && !result.Exists (entry))
  151. result.AddPermissionAccess (entry);
  152. }
  153. return result;
  154. }
  155. public override bool IsSubsetOf (IPermission target)
  156. {
  157. if (target == null) {
  158. #if NET_2_0
  159. // do not use Cast - different permissions (and earlier Fx) return false :-/
  160. return true;
  161. #else
  162. return false;
  163. #endif
  164. }
  165. ResourcePermissionBase rpb = (target as ResourcePermissionBase);
  166. if (rpb == null)
  167. return false;
  168. if (rpb.IsUnrestricted ())
  169. return true;
  170. if (IsUnrestricted ())
  171. return rpb.IsUnrestricted ();
  172. foreach (ResourcePermissionBaseEntry entry in _list) {
  173. if (!rpb.Exists (entry))
  174. return false;
  175. }
  176. return true;
  177. }
  178. public bool IsUnrestricted ()
  179. {
  180. return _unrestricted;
  181. }
  182. protected void RemovePermissionAccess (ResourcePermissionBaseEntry entry)
  183. {
  184. CheckEntry (entry);
  185. for (int i = 0; i < _list.Count; i++) {
  186. ResourcePermissionBaseEntry rpbe = (ResourcePermissionBaseEntry) _list [i];
  187. if (Equals (entry, rpbe)) {
  188. _list.RemoveAt (i);
  189. return;
  190. }
  191. }
  192. string msg = Locale.GetText ("Entry doesn't exists.");
  193. throw new InvalidOperationException (msg);
  194. }
  195. public override SecurityElement ToXml ()
  196. {
  197. SecurityElement se = PermissionHelper.Element (this.GetType (), version);
  198. if (IsUnrestricted ()) {
  199. se.AddAttribute ("Unrestricted", "true");
  200. }
  201. else {
  202. foreach (ResourcePermissionBaseEntry entry in _list) {
  203. SecurityElement container = se;
  204. string access = null;
  205. if (PermissionAccessType != null)
  206. access = Enum.Format (PermissionAccessType, entry.PermissionAccess, "g");
  207. for (int i=0; i < _tags.Length; i++) {
  208. SecurityElement child = new SecurityElement (_tags [i]);
  209. child.AddAttribute ("name", entry.PermissionAccessPath [i]);
  210. if (access != null)
  211. child.AddAttribute ("access", access);
  212. container.AddChild (child);
  213. child = container;
  214. }
  215. }
  216. }
  217. return se;
  218. }
  219. public override IPermission Union (IPermission target)
  220. {
  221. ResourcePermissionBase rpb = Cast (target);
  222. if (rpb == null)
  223. return Copy ();
  224. if (IsEmpty () && rpb.IsEmpty ())
  225. return null;
  226. if (rpb.IsEmpty ())
  227. return Copy ();
  228. if (IsEmpty ())
  229. return rpb.Copy ();
  230. bool unrestricted = (IsUnrestricted () || rpb.IsUnrestricted ());
  231. ResourcePermissionBase result = CreateFromType (this.GetType (), unrestricted);
  232. // strangely unrestricted union doesn't process the elements (while intersect does)
  233. if (!unrestricted) {
  234. foreach (ResourcePermissionBaseEntry entry in _list) {
  235. result.AddPermissionAccess (entry);
  236. }
  237. foreach (ResourcePermissionBaseEntry entry in rpb._list) {
  238. // don't add twice
  239. if (!result.Exists (entry))
  240. result.AddPermissionAccess (entry);
  241. }
  242. }
  243. return result;
  244. }
  245. // helpers
  246. private bool IsEmpty ()
  247. {
  248. return (!_unrestricted && (_list.Count == 0));
  249. }
  250. private ResourcePermissionBase Cast (IPermission target)
  251. {
  252. if (target == null)
  253. return null;
  254. ResourcePermissionBase rp = (target as ResourcePermissionBase);
  255. if (rp == null) {
  256. PermissionHelper.ThrowInvalidPermission (target, typeof (ResourcePermissionBase));
  257. }
  258. return rp;
  259. }
  260. internal void CheckEntry (ResourcePermissionBaseEntry entry)
  261. {
  262. if (entry == null)
  263. throw new ArgumentNullException ("entry");
  264. if ((entry.PermissionAccessPath == null) || (entry.PermissionAccessPath.Length != _tags.Length)) {
  265. string msg = Locale.GetText ("Entry doesn't match TagNames");
  266. throw new InvalidOperationException (msg);
  267. }
  268. }
  269. internal bool Equals (ResourcePermissionBaseEntry entry1, ResourcePermissionBaseEntry entry2)
  270. {
  271. if (entry1.PermissionAccess != entry2.PermissionAccess)
  272. return false;
  273. if (entry1.PermissionAccessPath.Length != entry2.PermissionAccessPath.Length)
  274. return false;
  275. for (int i=0; i < entry1.PermissionAccessPath.Length; i++) {
  276. if (entry1.PermissionAccessPath [i] != entry2.PermissionAccessPath [i])
  277. return false;
  278. }
  279. return true;
  280. }
  281. internal bool Exists (ResourcePermissionBaseEntry entry)
  282. {
  283. if (_list.Count == 0)
  284. return false;
  285. foreach (ResourcePermissionBaseEntry rpbe in _list) {
  286. if (Equals (rpbe, entry))
  287. return true;
  288. }
  289. return false;
  290. }
  291. // logic isn't identical to PermissionHelper.CheckSecurityElement
  292. // - no throw on version mismatch
  293. internal int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
  294. {
  295. if (se == null)
  296. throw new ArgumentNullException (parameterName);
  297. #if NET_2_0
  298. // Tag is case-sensitive
  299. if (se.Tag != "IPermission") {
  300. string msg = String.Format (Locale.GetText ("Invalid tag {0}"), se.Tag);
  301. throw new ArgumentException (msg, parameterName);
  302. }
  303. #endif
  304. // Note: we do not care about the class attribute at
  305. // this stage (in fact we don't even if the class
  306. // attribute is present or not). Anyway the object has
  307. // already be created, with success, if we're loading it
  308. // we assume minimum version if no version number is supplied
  309. int version = minimumVersion;
  310. string v = se.Attribute ("version");
  311. if (v != null) {
  312. try {
  313. version = Int32.Parse (v);
  314. }
  315. catch (Exception e) {
  316. string msg = Locale.GetText ("Couldn't parse version from '{0}'.");
  317. msg = String.Format (msg, v);
  318. throw new ArgumentException (msg, parameterName, e);
  319. }
  320. }
  321. #if NET_2_0
  322. if ((version < minimumVersion) || (version > maximumVersion)) {
  323. string msg = Locale.GetText ("Unknown version '{0}', expected versions between ['{1}','{2}'].");
  324. msg = String.Format (msg, version, minimumVersion, maximumVersion);
  325. throw new ArgumentException (msg, parameterName);
  326. }
  327. #endif
  328. return version;
  329. }
  330. // static helpers
  331. private static char[] invalidChars = new char[] { '\t', '\n', '\v', '\f', '\r', ' ', '\\', '\x160' };
  332. internal static void ValidateMachineName (string name)
  333. {
  334. // FIXME: maybe other checks are required (but not documented)
  335. if ((name == null) || (name.Length == 0) || (name.IndexOfAny (invalidChars) != -1)) {
  336. string msg = Locale.GetText ("Invalid machine name '{0}'.");
  337. if (name == null)
  338. name = "(null)";
  339. msg = String.Format (msg, name);
  340. throw new ArgumentException (msg, "MachineName");
  341. }
  342. }
  343. internal static ResourcePermissionBase CreateFromType (Type type, bool unrestricted)
  344. {
  345. object[] parameters = new object [1];
  346. parameters [0] = (object) ((unrestricted) ? PermissionState.Unrestricted : PermissionState.None);
  347. // we must return the derived type - this is why an empty constructor is required ;-)
  348. return (ResourcePermissionBase) Activator.CreateInstance (type, parameters);
  349. }
  350. }
  351. }