GenericAce.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. //
  2. // System.Security.AccessControl.GenericAce implementation
  3. //
  4. // Authors:
  5. // Dick Porter <[email protected]>
  6. // Atsushi Enomoto <[email protected]>
  7. // Kenneth Bell
  8. //
  9. // Copyright (C) 2006-2007 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.Globalization;
  31. using System.Security.Principal;
  32. using System.Text;
  33. namespace System.Security.AccessControl {
  34. public abstract class GenericAce
  35. {
  36. private AceFlags ace_flags;
  37. private AceType ace_type;
  38. internal GenericAce (AceType type, AceFlags flags)
  39. {
  40. if (type > AceType.MaxDefinedAceType) {
  41. throw new ArgumentOutOfRangeException ("type");
  42. }
  43. this.ace_type = type;
  44. this.ace_flags = flags;
  45. }
  46. internal GenericAce(byte[] binaryForm, int offset)
  47. {
  48. if (binaryForm == null)
  49. throw new ArgumentNullException("binaryForm");
  50. if (offset < 0 || offset > binaryForm.Length - 2)
  51. throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
  52. ace_type = (AceType)binaryForm[offset];
  53. ace_flags = (AceFlags)binaryForm[offset + 1];
  54. }
  55. public AceFlags AceFlags {
  56. get { return ace_flags; }
  57. set { ace_flags = value; }
  58. }
  59. public AceType AceType {
  60. get { return ace_type; }
  61. }
  62. public AuditFlags AuditFlags {
  63. get {
  64. AuditFlags ret = AuditFlags.None;
  65. if ((ace_flags & AceFlags.SuccessfulAccess) != 0)
  66. ret |= AuditFlags.Success;
  67. if ((ace_flags & AceFlags.FailedAccess) != 0)
  68. ret |= AuditFlags.Failure;
  69. return ret;
  70. }
  71. }
  72. public abstract int BinaryLength { get; }
  73. public InheritanceFlags InheritanceFlags {
  74. get {
  75. InheritanceFlags ret = InheritanceFlags.None;
  76. if ((ace_flags & AceFlags.ObjectInherit) != 0)
  77. ret |= InheritanceFlags.ObjectInherit;
  78. if ((ace_flags & AceFlags.ContainerInherit) != 0)
  79. ret |= InheritanceFlags.ContainerInherit;
  80. return ret;
  81. }
  82. }
  83. public bool IsInherited {
  84. get { return (ace_flags & AceFlags.Inherited) != AceFlags.None; }
  85. }
  86. public PropagationFlags PropagationFlags {
  87. get {
  88. PropagationFlags ret = PropagationFlags.None;
  89. if ((ace_flags & AceFlags.InheritOnly) != 0)
  90. ret |= PropagationFlags.InheritOnly;
  91. if ((ace_flags & AceFlags.NoPropagateInherit) != 0)
  92. ret |= PropagationFlags.NoPropagateInherit;
  93. return ret;
  94. }
  95. }
  96. public GenericAce Copy ()
  97. {
  98. byte[] buffer = new byte[BinaryLength];
  99. GetBinaryForm(buffer, 0);
  100. return GenericAce.CreateFromBinaryForm(buffer, 0);
  101. }
  102. public static GenericAce CreateFromBinaryForm (byte[] binaryForm, int offset)
  103. {
  104. if (binaryForm == null)
  105. throw new ArgumentNullException("binaryForm");
  106. if (offset < 0 || offset > binaryForm.Length - 1)
  107. throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
  108. AceType type = (AceType)binaryForm[offset];
  109. if (IsObjectType(type))
  110. return new ObjectAce(binaryForm, offset);
  111. else
  112. return new CommonAce(binaryForm, offset);
  113. }
  114. public override sealed bool Equals (object o)
  115. {
  116. return this == (o as GenericAce);
  117. }
  118. public abstract void GetBinaryForm (byte[] binaryForm, int offset);
  119. public override sealed int GetHashCode ()
  120. {
  121. byte[] buffer = new byte[BinaryLength];
  122. GetBinaryForm(buffer, 0);
  123. int code = 0;
  124. for(int i = 0; i < buffer.Length; ++i)
  125. {
  126. code = (code << 3) | ((code >> 29) & 0x7);
  127. code ^= ((int)buffer[i]) & 0xff;
  128. }
  129. return code;
  130. }
  131. public static bool operator== (GenericAce left, GenericAce right)
  132. {
  133. if(((object)left) == null)
  134. return((object)right) == null;
  135. if(((object)right) == null)
  136. return false;
  137. int leftLen = left.BinaryLength;
  138. int rightLen = right.BinaryLength;
  139. if( leftLen != rightLen)
  140. return false;
  141. byte[] leftBuffer = new byte[leftLen];
  142. byte[] rightBuffer = new byte[rightLen];
  143. left.GetBinaryForm(leftBuffer, 0);
  144. right.GetBinaryForm(rightBuffer, 0);
  145. for(int i = 0; i < leftLen; ++i) {
  146. if(leftBuffer[i] != rightBuffer[i])
  147. return false;
  148. }
  149. return true;
  150. }
  151. public static bool operator!= (GenericAce left, GenericAce right)
  152. {
  153. if(((object)left) == null)
  154. return((object)right) != null;
  155. if(((object)right) == null)
  156. return true;
  157. int leftLen = left.BinaryLength;
  158. int rightLen = right.BinaryLength;
  159. if( leftLen != rightLen)
  160. return true;
  161. byte[] leftBuffer = new byte[leftLen];
  162. byte[] rightBuffer = new byte[rightLen];
  163. left.GetBinaryForm(leftBuffer, 0);
  164. right.GetBinaryForm(rightBuffer, 0);
  165. for(int i = 0; i < leftLen; ++i) {
  166. if(leftBuffer[i] != rightBuffer[i])
  167. return true;
  168. }
  169. return false;
  170. }
  171. internal abstract string GetSddlForm();
  172. static internal GenericAce CreateFromSddlForm (string sddlForm, ref int pos)
  173. {
  174. if (sddlForm[pos] != '(')
  175. throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
  176. int endPos = sddlForm.IndexOf (')', pos);
  177. if (endPos < 0)
  178. throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
  179. int count = endPos - (pos + 1);
  180. string elementsStr = sddlForm.Substring (pos + 1,
  181. count);
  182. elementsStr = elementsStr.ToUpperInvariant ();
  183. string[] elements = elementsStr.Split (';');
  184. if (elements.Length != 6)
  185. throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
  186. ObjectAceFlags objFlags = ObjectAceFlags.None;
  187. AceType type = ParseSddlAceType (elements[0]);
  188. AceFlags flags = ParseSddlAceFlags (elements[1]);
  189. int accessMask = ParseSddlAccessRights (elements[2]);
  190. Guid objectType = Guid.Empty;
  191. if (!string.IsNullOrEmpty (elements[3])) {
  192. objectType = new Guid(elements[3]);
  193. objFlags |= ObjectAceFlags.ObjectAceTypePresent;
  194. }
  195. Guid inhObjectType = Guid.Empty;
  196. if (!string.IsNullOrEmpty (elements[4])) {
  197. inhObjectType = new Guid(elements[4]);
  198. objFlags |= ObjectAceFlags.InheritedObjectAceTypePresent;
  199. }
  200. SecurityIdentifier sid
  201. = new SecurityIdentifier (elements[5]);
  202. if (type == AceType.AccessAllowedCallback
  203. || type == AceType.AccessDeniedCallback)
  204. throw new NotImplementedException ("Conditional ACEs not supported");
  205. pos = endPos + 1;
  206. if (IsObjectType(type))
  207. return new ObjectAce(type, flags, accessMask, sid, objFlags, objectType, inhObjectType, null);
  208. else {
  209. if (objFlags != ObjectAceFlags.None)
  210. throw new ArgumentException( "Invalid SDDL string.", "sddlForm");
  211. return new CommonAce (type, flags, accessMask, sid, null);
  212. }
  213. }
  214. private static bool IsObjectType(AceType type)
  215. {
  216. return type == AceType.AccessAllowedCallbackObject
  217. || type == AceType.AccessAllowedObject
  218. || type == AceType.AccessDeniedCallbackObject
  219. || type == AceType.AccessDeniedObject
  220. || type == AceType.SystemAlarmCallbackObject
  221. || type == AceType.SystemAlarmObject
  222. || type == AceType.SystemAuditCallbackObject
  223. || type == AceType.SystemAuditObject;
  224. }
  225. internal static string GetSddlAceType (AceType type)
  226. {
  227. switch (type) {
  228. case AceType.AccessAllowed:
  229. return "A";
  230. case AceType.AccessDenied:
  231. return "D";
  232. case AceType.AccessAllowedObject:
  233. return "OA";
  234. case AceType.AccessDeniedObject:
  235. return "OD";
  236. case AceType.SystemAudit:
  237. return "AU";
  238. case AceType.SystemAlarm:
  239. return "AL";
  240. case AceType.SystemAuditObject:
  241. return "OU";
  242. case AceType.SystemAlarmObject:
  243. return "OL";
  244. case AceType.AccessAllowedCallback:
  245. return "XA";
  246. case AceType.AccessDeniedCallback:
  247. return "XD";
  248. default:
  249. throw new ArgumentException ("Unable to convert to SDDL ACE type: " + type, "type");
  250. }
  251. }
  252. private static AceType ParseSddlAceType (string type)
  253. {
  254. switch (type) {
  255. case "A":
  256. return AceType.AccessAllowed;
  257. case "D":
  258. return AceType.AccessDenied;
  259. case "OA":
  260. return AceType.AccessAllowedObject;
  261. case "OD":
  262. return AceType.AccessDeniedObject;
  263. case "AU":
  264. return AceType.SystemAudit;
  265. case "AL":
  266. return AceType.SystemAlarm;
  267. case "OU":
  268. return AceType.SystemAuditObject;
  269. case "OL":
  270. return AceType.SystemAlarmObject;
  271. case "XA":
  272. return AceType.AccessAllowedCallback;
  273. case "XD":
  274. return AceType.AccessDeniedCallback;
  275. default:
  276. throw new ArgumentException ("Unable to convert SDDL to ACE type: " + type, "type");
  277. }
  278. }
  279. internal static string GetSddlAceFlags (AceFlags flags)
  280. {
  281. StringBuilder result = new StringBuilder ();
  282. if ((flags & AceFlags.ObjectInherit) != 0)
  283. result.Append ("OI");
  284. if ((flags & AceFlags.ContainerInherit) != 0)
  285. result.Append ("CI");
  286. if ((flags & AceFlags.NoPropagateInherit) != 0)
  287. result.Append ("NP");
  288. if ((flags & AceFlags.InheritOnly) != 0)
  289. result.Append ("IO");
  290. if ((flags & AceFlags.Inherited) != 0)
  291. result.Append ("ID");
  292. if ((flags & AceFlags.SuccessfulAccess) != 0)
  293. result.Append ("SA");
  294. if ((flags & AceFlags.FailedAccess) != 0)
  295. result.Append ("FA");
  296. return result.ToString ();
  297. }
  298. private static AceFlags ParseSddlAceFlags (string flags)
  299. {
  300. AceFlags ret = AceFlags.None;
  301. int pos = 0;
  302. while (pos < flags.Length - 1) {
  303. string flag = flags.Substring (pos, 2);
  304. switch (flag) {
  305. case "CI":
  306. ret |= AceFlags.ContainerInherit;
  307. break;
  308. case "OI":
  309. ret |= AceFlags.ObjectInherit;
  310. break;
  311. case "NP":
  312. ret |= AceFlags.NoPropagateInherit;
  313. break;
  314. case "IO":
  315. ret |= AceFlags.InheritOnly;
  316. break;
  317. case "ID":
  318. ret |= AceFlags.Inherited;
  319. break;
  320. case "SA":
  321. ret |= AceFlags.SuccessfulAccess;
  322. break;
  323. case "FA":
  324. ret |= AceFlags.FailedAccess;
  325. break;
  326. default:
  327. throw new ArgumentException ("Invalid SDDL string.", "flags");
  328. }
  329. pos += 2;
  330. }
  331. if (pos != flags.Length)
  332. throw new ArgumentException ("Invalid SDDL string.", "flags");
  333. return ret;
  334. }
  335. private static int ParseSddlAccessRights (string accessMask)
  336. {
  337. if (accessMask.StartsWith ("0X")) {
  338. return int.Parse (accessMask.Substring (2),
  339. NumberStyles.HexNumber,
  340. CultureInfo.InvariantCulture);
  341. } else if (Char.IsDigit (accessMask, 0)) {
  342. return int.Parse (accessMask,
  343. NumberStyles.Integer,
  344. CultureInfo.InvariantCulture);
  345. } else {
  346. return ParseSddlAliasRights (accessMask);
  347. }
  348. }
  349. private static int ParseSddlAliasRights(string accessMask)
  350. {
  351. int ret = 0;
  352. int pos = 0;
  353. while (pos < accessMask.Length - 1) {
  354. string flag = accessMask.Substring (pos, 2);
  355. SddlAccessRight right = SddlAccessRight.LookupByName(flag);
  356. if (right == null)
  357. throw new ArgumentException ("Invalid SDDL string.", "accessMask");
  358. ret |= right.Value;
  359. pos += 2;
  360. }
  361. if (pos != accessMask.Length)
  362. throw new ArgumentException ("Invalid SDDL string.", "accessMask");
  363. return ret;
  364. }
  365. internal static ushort ReadUShort (byte[] buffer, int offset)
  366. {
  367. return (ushort)((((int)buffer[offset + 0]) << 0)
  368. | (((int)buffer[offset + 1]) << 8));
  369. }
  370. internal static int ReadInt (byte[] buffer, int offset)
  371. {
  372. return (((int)buffer[offset + 0]) << 0)
  373. | (((int)buffer[offset + 1]) << 8)
  374. | (((int)buffer[offset + 2]) << 16)
  375. | (((int)buffer[offset + 3]) << 24);
  376. }
  377. internal static void WriteInt (int val, byte[] buffer, int offset)
  378. {
  379. buffer[offset] = (byte)val;
  380. buffer[offset + 1] = (byte)(val >> 8);
  381. buffer[offset + 2] = (byte)(val >> 16);
  382. buffer[offset + 3] = (byte)(val >> 24);
  383. }
  384. internal static void WriteUShort (ushort val, byte[] buffer,
  385. int offset)
  386. {
  387. buffer[offset] = (byte)val;
  388. buffer[offset + 1] = (byte)(val >> 8);
  389. }
  390. }
  391. }