2 // permview.cs: Managed Permission Viewer for .NET assemblies
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2004-2007 Novell, Inc (http://www.novell.com)
11 using System.Collections;
12 using System.Collections.Generic;
14 using System.Reflection;
15 using System.Security;
16 using SSP = System.Security.Permissions;
21 [assembly: AssemblyTitle ("Mono PermView")]
22 [assembly: AssemblyDescription ("Managed Permission Viewer for .NET assemblies")]
24 namespace Mono.Tools {
26 static class SecurityDeclarationRocks {
28 public static PermissionSet ToPermissionSet (this SecurityDeclaration self)
31 throw new ArgumentNullException ("self");
34 if (TryProcessPermissionSetAttribute (self, out set))
37 return CreatePermissionSet (self);
40 static bool TryProcessPermissionSetAttribute (SecurityDeclaration declaration, out PermissionSet set)
44 if (!declaration.HasSecurityAttributes && declaration.SecurityAttributes.Count != 1)
47 var security_attribute = declaration.SecurityAttributes [0];
48 var attribute_type = security_attribute.AttributeType;
50 if (attribute_type.Name != "PermissionSetAttribute" || attribute_type.Namespace != "System.Security.Permissions")
53 var named_argument = security_attribute.Properties [0];
54 if (named_argument.Name != "XML")
55 throw new NotSupportedException ();
57 var attribute = new SSP.PermissionSetAttribute ((SSP.SecurityAction) declaration.Action);
58 attribute.XML = (string) named_argument.Argument.Value;
60 set = attribute.CreatePermissionSet ();
64 static PermissionSet CreatePermissionSet (SecurityDeclaration declaration)
66 var set = new PermissionSet (SSP.PermissionState.None);
68 foreach (var attribute in declaration.SecurityAttributes) {
69 var permission = CreatePermission (declaration, attribute);
70 set.AddPermission (permission);
76 static IPermission CreatePermission (SecurityDeclaration declaration, SecurityAttribute attribute)
78 var attribute_type = Type.GetType (attribute.AttributeType.FullName);
79 if (attribute_type == null)
80 throw new ArgumentException ();
82 var security_attribute = CreateSecurityAttribute (attribute_type, declaration);
83 if (security_attribute == null)
84 throw new InvalidOperationException ();
86 CompleteSecurityAttribute (security_attribute, attribute);
88 return security_attribute.CreatePermission ();
91 static void CompleteSecurityAttribute (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute)
93 if (attribute.HasFields)
94 CompleteSecurityAttributeFields (security_attribute, attribute);
96 if (attribute.HasProperties)
97 CompleteSecurityAttributeProperties (security_attribute, attribute);
100 static void CompleteSecurityAttributeFields (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute)
102 var type = security_attribute.GetType ();
104 foreach (var named_argument in attribute.Fields)
105 type.GetField (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value);
108 static void CompleteSecurityAttributeProperties (SSP.SecurityAttribute security_attribute, SecurityAttribute attribute)
110 var type = security_attribute.GetType ();
112 foreach (var named_argument in attribute.Properties)
113 type.GetProperty (named_argument.Name).SetValue (security_attribute, named_argument.Argument.Value, null);
116 static SSP.SecurityAttribute CreateSecurityAttribute (Type attribute_type, SecurityDeclaration declaration)
118 SSP.SecurityAttribute security_attribute;
120 security_attribute = (SSP.SecurityAttribute) Activator.CreateInstance (
121 attribute_type, new object [] { (SSP.SecurityAction) declaration.Action });
122 } catch (MissingMethodException) {
123 security_attribute = (SSP.SecurityAttribute) Activator.CreateInstance (attribute_type, new object [0]);
126 return security_attribute;
130 class SecurityElementComparer : IComparer {
132 public int Compare (object x, object y)
134 SecurityElement sx = (x as SecurityElement);
135 SecurityElement sy = (y as SecurityElement);
137 return (sy == null) ? 0 : -1;
141 // compare by name (type name, method name, action name)
142 return String.Compare (sx.Attribute ("Name"), sy.Attribute ("Name"));
148 private const string NotSpecified = "\tNot specified.";
150 static private void Help ()
152 Console.WriteLine ("Usage: permview [options] assembly{0}", Environment.NewLine);
153 Console.WriteLine ("where options are:");
154 Console.WriteLine (" -output filename Output information into specified file.");
155 Console.WriteLine (" -decl Show declarative security attributes on classes and methods.");
156 Console.WriteLine (" -xml Output in XML format");
157 Console.WriteLine (" -help Show help informations (this text)");
158 Console.WriteLine ();
161 static bool declarative = false;
162 static bool xmloutput = false;
164 static TextWriter ProcessOptions (string[] args)
166 TextWriter tw = Console.Out;
167 for (int i=0; i < args.Length - 1; i++) {
168 switch (args [i].ToUpper ()) {
177 tw = (TextWriter) new StreamWriter (args [++i]);
199 static bool ProcessAssemblyOnly (TextWriter tw, AssemblyDefinition ad)
202 string minimal = NotSpecified + Environment.NewLine;
203 string optional = NotSpecified + Environment.NewLine;
204 string refused = NotSpecified + Environment.NewLine;
206 foreach (SecurityDeclaration decl in ad.SecurityDeclarations) {
207 switch (decl.Action) {
208 case Mono.Cecil.SecurityAction.RequestMinimum:
209 minimal = decl.ToPermissionSet ().ToString ();
211 case Mono.Cecil.SecurityAction.RequestOptional:
212 optional = decl.ToPermissionSet ().ToString ();
214 case Mono.Cecil.SecurityAction.RequestRefuse:
215 refused = decl.ToPermissionSet ().ToString ();
218 tw.WriteLine ("Invalid assembly level declaration {0}{1}{2}",
219 decl.Action, Environment.NewLine, decl.ToPermissionSet ());
225 tw.WriteLine ("Minimal Permission Set:");
226 tw.WriteLine (minimal);
227 tw.WriteLine ("Optional Permission Set:");
228 tw.WriteLine (optional);
229 tw.WriteLine ("Refused Permission Set:");
230 tw.WriteLine (refused);
234 static void ShowSecurity (TextWriter tw, string header, IEnumerable<SecurityDeclaration> declarations)
236 foreach (SecurityDeclaration declsec in declarations) {
237 tw.WriteLine ("{0} {1} Permission Set:{2}{3}", header,
238 declsec.Action, Environment.NewLine, declsec.ToPermissionSet ());
242 static bool ProcessAssemblyComplete (TextWriter tw, AssemblyDefinition ad)
244 if (ad.SecurityDeclarations.Count > 0) {
245 ShowSecurity (tw, "Assembly", ad.SecurityDeclarations);
248 foreach (ModuleDefinition module in ad.Modules) {
250 foreach (TypeDefinition type in module.Types) {
252 if (type.SecurityDeclarations.Count > 0) {
253 ShowSecurity (tw, "Class " + type.ToString (), ad.SecurityDeclarations);
256 foreach (MethodDefinition method in type.Methods) {
257 if (method.SecurityDeclarations.Count > 0) {
258 ShowSecurity (tw, "Method " + method.ToString (), method.SecurityDeclarations);
266 static void AddAttribute (SecurityElement se, string attr, string value)
268 value = value.Replace ("&", "&");
269 se.AddAttribute (attr, value);
272 static SecurityElement AddSecurityXml (IEnumerable<SecurityDeclaration> declarations)
274 ArrayList list = new ArrayList ();
275 foreach (SecurityDeclaration declsec in declarations) {
276 SecurityElement child = new SecurityElement ("Action");
277 AddAttribute (child, "Name", declsec.Action.ToString ());
278 child.AddChild (declsec.ToPermissionSet ().ToXml ());
282 list.Sort (Comparer);
284 SecurityElement se = new SecurityElement ("Actions");
285 foreach (SecurityElement child in list) {
291 static SecurityElementComparer comparer;
292 static IComparer Comparer {
294 if (comparer == null)
295 comparer = new SecurityElementComparer ();
300 static bool ProcessAssemblyXml (TextWriter tw, AssemblyDefinition ad)
302 SecurityElement se = new SecurityElement ("Assembly");
303 se.AddAttribute ("Name", ad.Name.FullName);
305 if (ad.SecurityDeclarations.Count > 0) {
306 se.AddChild (AddSecurityXml (ad.SecurityDeclarations));
309 ArrayList tlist = new ArrayList ();
310 ArrayList mlist = new ArrayList ();
312 foreach (ModuleDefinition module in ad.Modules) {
314 foreach (TypeDefinition type in module.Types) {
316 SecurityElement klass = new SecurityElement ("Class");
317 SecurityElement methods = new SecurityElement ("Methods");
319 SecurityElement typelem = null;
320 if (type.SecurityDeclarations.Count > 0) {
321 typelem = AddSecurityXml (type.SecurityDeclarations);
327 foreach (MethodDefinition method in type.Methods) {
328 if (method.SecurityDeclarations.Count > 0) {
329 SecurityElement meth = new SecurityElement ("Method");
330 AddAttribute (meth, "Name", method.ToString ());
331 meth.AddChild (AddSecurityXml (method.SecurityDeclarations));
337 mlist.Sort (Comparer);
338 foreach (SecurityElement method in mlist) {
339 methods.AddChild (method);
342 if ((typelem != null) || ((methods.Children != null) && (methods.Children.Count > 0))) {
343 AddAttribute (klass, "Name", type.ToString ());
345 klass.AddChild (typelem);
346 if ((methods.Children != null) && (methods.Children.Count > 0))
347 klass.AddChild (methods);
353 tlist.Sort (Comparer);
354 foreach (SecurityElement type in tlist) {
359 tw.WriteLine (se.ToString ());
364 static int Main (string[] args)
367 Console.WriteLine (new AssemblyInfo ().ToString ());
368 if (args.Length == 0) {
373 TextWriter tw = ProcessOptions (args);
377 string assemblyName = args [args.Length - 1];
378 AssemblyDefinition ad = AssemblyDefinition.ReadAssembly (assemblyName);
380 bool complete = false;
383 // full output (assembly+classes+methods)
384 complete = ProcessAssemblyComplete (tw, ad);
385 } else if (xmloutput) {
386 // full output in XML (for easier diffs after c14n)
387 complete = ProcessAssemblyXml (tw, ad);
389 // default (assembly only)
390 complete = ProcessAssemblyOnly (tw, ad);
394 Console.Error.WriteLine ("Couldn't reflect informations.");
398 Console.Error.WriteLine ("Couldn't load assembly '{0}'.", assemblyName);
403 catch (Exception e) {
404 Console.Error.WriteLine ("Error: " + e.ToString ());