Merge branch 'master' of http://github.com/mono/mono
[mono.git] / mcs / tools / security / permview.cs
1 //
2 // permview.cs: Managed Permission Viewer for .NET assemblies
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2004-2007 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.IO;
13 using System.Reflection;
14 using System.Security;
15 using System.Security.Permissions;
16 using System.Text;
17
18 using Mono.Cecil;
19
20 [assembly: AssemblyTitle ("Mono PermView")]
21 [assembly: AssemblyDescription ("Managed Permission Viewer for .NET assemblies")]
22
23 namespace Mono.Tools {
24
25         class SecurityElementComparer : IComparer {
26
27                 public int Compare (object x, object y)
28                 {
29                         SecurityElement sx = (x as SecurityElement);
30                         SecurityElement sy = (y as SecurityElement);
31                         if (sx == null)
32                                 return (sy == null) ? 0 : -1;
33                         else if (sy == null)
34                                 return 1;
35
36                         // compare by name (type name, method name, action name)
37                         return String.Compare (sx.Attribute ("Name"), sy.Attribute ("Name"));
38                 }
39         }
40
41         class PermView {
42
43                 private const string NotSpecified = "\tNot specified.";
44
45                 static private void Help () 
46                 {
47                         Console.WriteLine ("Usage: permview [options] assembly{0}", Environment.NewLine);
48                         Console.WriteLine ("where options are:");
49                         Console.WriteLine (" -output filename  Output information into specified file.");
50                         Console.WriteLine (" -decl             Show declarative security attributes on classes and methods.");
51                         Console.WriteLine (" -xml              Output in XML format");
52                         Console.WriteLine (" -help             Show help informations (this text)");
53                         Console.WriteLine ();
54                 }
55
56                 static bool declarative = false;
57                 static bool xmloutput = false;
58
59                 static TextWriter ProcessOptions (string[] args)
60                 {
61                         TextWriter tw = Console.Out;
62                         for (int i=0; i < args.Length - 1; i++) {
63                                 switch (args [i].ToUpper ()) {
64                                 case "/DECL":
65                                 case "-DECL":
66                                 case "--DECL":
67                                         declarative = true;
68                                         break;
69                                 case "/OUTPUT":
70                                 case "-OUTPUT":
71                                 case "--OUTPUT":
72                                         tw = (TextWriter) new StreamWriter (args [++i]);
73                                         break;
74                                 case "/XML":
75                                 case "-XML":
76                                 case "--XML":
77                                         xmloutput = true;
78                                         break;
79                                 case "/HELP":
80                                 case "/H":
81                                 case "-HELP":
82                                 case "-H":
83                                 case "--HELP":
84                                 case "--H":
85                                 case "-?":
86                                 case "--?":
87                                         Help ();
88                                         return null;
89                                 }
90                         }
91                         return tw;
92                 }
93
94                 static bool ProcessAssemblyOnly (TextWriter tw, AssemblyDefinition ad) 
95                 {
96                         bool result = true;
97                         string minimal = NotSpecified + Environment.NewLine;
98                         string optional = NotSpecified + Environment.NewLine;
99                         string refused = NotSpecified + Environment.NewLine;
100
101                         foreach (SecurityDeclaration decl in ad.SecurityDeclarations) {
102                                 switch (decl.Action) {
103                                 case Mono.Cecil.SecurityAction.RequestMinimum:
104                                         minimal = decl.PermissionSet.ToString ();
105                                         break;
106                                 case Mono.Cecil.SecurityAction.RequestOptional:
107                                         optional = decl.PermissionSet.ToString ();
108                                         break;
109                                 case Mono.Cecil.SecurityAction.RequestRefuse:
110                                         refused = decl.PermissionSet.ToString ();
111                                         break;
112                                 default:
113                                         tw.WriteLine ("Invalid assembly level declaration {0}{1}{2}",
114                                                 decl.Action, Environment.NewLine, decl.PermissionSet);
115                                         result = false;
116                                         break;
117                                 }
118                         }
119
120                         tw.WriteLine ("Minimal Permission Set:");
121                         tw.WriteLine (minimal);
122                         tw.WriteLine ("Optional Permission Set:");
123                         tw.WriteLine (optional);
124                         tw.WriteLine ("Refused Permission Set:");
125                         tw.WriteLine (refused);
126                         return result;
127                 }
128
129                 static void ShowSecurity (TextWriter tw, string header, SecurityDeclarationCollection declarations)
130                 {
131                         foreach (SecurityDeclaration declsec in declarations) {
132                                 tw.WriteLine ("{0} {1} Permission Set:{2}{3}", header,
133                                         declsec.Action, Environment.NewLine, declsec.PermissionSet);
134                         }
135                 }
136
137                 static bool ProcessAssemblyComplete (TextWriter tw, AssemblyDefinition ad)
138                 {
139                         if (ad.SecurityDeclarations.Count > 0) {
140                                 ShowSecurity (tw, "Assembly", ad.SecurityDeclarations);
141                         }
142
143                         foreach (ModuleDefinition module in ad.Modules) {
144
145                                 foreach (TypeDefinition type in module.Types) {
146
147                                         if (type.SecurityDeclarations.Count > 0) {
148                                                 ShowSecurity (tw, "Class " + type.ToString (), ad.SecurityDeclarations);
149                                         }
150
151                                         foreach (MethodDefinition method in type.Methods) {
152                                                 if (method.SecurityDeclarations.Count > 0) {
153                                                         ShowSecurity (tw, "Method " + method.ToString (), method.SecurityDeclarations);
154                                                 }
155                                         }
156                                 }
157                         }
158                         return true;
159                 }
160
161                 static void AddAttribute (SecurityElement se, string attr, string value)
162                 {
163                         value = value.Replace ("&", "&amp;");
164                         se.AddAttribute (attr, value);
165                 }
166
167                 static SecurityElement AddSecurityXml (SecurityDeclarationCollection declarations)
168                 {
169                         ArrayList list = new ArrayList ();
170                         foreach (SecurityDeclaration declsec in declarations) {
171                                 SecurityElement child = new SecurityElement ("Action");
172                                 AddAttribute (child, "Name", declsec.Action.ToString ());
173                                 child.AddChild (declsec.PermissionSet.ToXml ());
174                                 list.Add (child);
175                         }
176                         // sort actions
177                         list.Sort (Comparer);
178
179                         SecurityElement se = new SecurityElement ("Actions");
180                         foreach (SecurityElement child in list) {
181                                 se.AddChild (child);
182                         }
183                         return se;
184                 }
185
186                 static SecurityElementComparer comparer;
187                 static IComparer Comparer {
188                         get {
189                                 if (comparer == null)
190                                         comparer = new SecurityElementComparer ();
191                                 return comparer;
192                         }
193                 }
194
195                 static bool ProcessAssemblyXml (TextWriter tw, AssemblyDefinition ad)
196                 {
197                         SecurityElement se = new SecurityElement ("Assembly");
198                         se.AddAttribute ("Name", ad.Name.FullName);
199
200                         if (ad.SecurityDeclarations.Count > 0) {
201                                 se.AddChild (AddSecurityXml (ad.SecurityDeclarations));
202                         }
203
204                         ArrayList tlist = new ArrayList ();
205                         ArrayList mlist = new ArrayList ();
206
207                         foreach (ModuleDefinition module in ad.Modules) {
208
209                                 foreach (TypeDefinition type in module.Types) {
210
211                                         SecurityElement klass = new SecurityElement ("Class");
212                                         SecurityElement methods = new SecurityElement ("Methods");
213
214                                         SecurityElement typelem = null;
215                                         if (type.SecurityDeclarations.Count > 0) {
216                                                 typelem = AddSecurityXml (type.SecurityDeclarations);
217                                         }
218
219                                         if (mlist.Count > 0)
220                                                 mlist.Clear ();
221
222                                         foreach (MethodDefinition method in type.Methods) {
223                                                 if (method.SecurityDeclarations.Count > 0) {
224                                                         SecurityElement meth = new SecurityElement ("Method");
225                                                         AddAttribute (meth, "Name", method.ToString ());
226                                                         meth.AddChild (AddSecurityXml (method.SecurityDeclarations));
227                                                         mlist.Add (meth);
228                                                 }
229                                         }
230
231                                         // sort methods
232                                         mlist.Sort (Comparer);
233                                         foreach (SecurityElement method in mlist) {
234                                                 methods.AddChild (method);
235                                         }
236
237                                         if ((typelem != null) || ((methods.Children != null) && (methods.Children.Count > 0))) {
238                                                 AddAttribute (klass, "Name", type.ToString ());
239                                                 if (typelem != null)
240                                                         klass.AddChild (typelem);
241                                                 if ((methods.Children != null) && (methods.Children.Count > 0))
242                                                         klass.AddChild (methods);
243                                                 tlist.Add (klass);
244                                         }
245                                 }
246
247                                 // sort types
248                                 tlist.Sort (Comparer);
249                                 foreach (SecurityElement type in tlist) {
250                                         se.AddChild (type);
251                                 }
252                         }
253
254                         tw.WriteLine (se.ToString ());
255                         return true;
256                 }
257
258                 [STAThread]
259                 static int Main (string[] args) 
260                 {
261                         try {
262                                 Console.WriteLine (new AssemblyInfo ().ToString ());
263                                 if (args.Length == 0) {
264                                         Help ();
265                                         return 0;
266                                 }
267
268                                 TextWriter tw = ProcessOptions (args);
269                                 if (tw == null)
270                                         return 0;
271
272                                 string assemblyName = args [args.Length - 1];
273                                 AssemblyDefinition ad = AssemblyFactory.GetAssembly (assemblyName);
274                                 if (ad != null) {
275                                         bool complete = false;
276                                         
277                                         if (declarative) {
278                                                 // full output (assembly+classes+methods)
279                                                 complete = ProcessAssemblyComplete (tw, ad);
280                                         } else if (xmloutput) {
281                                                 // full output in XML (for easier diffs after c14n)
282                                                 complete = ProcessAssemblyXml (tw, ad);
283                                         } else {
284                                                 // default (assembly only)
285                                                 complete = ProcessAssemblyOnly (tw, ad);
286                                         }
287
288                                         if (!complete) {
289                                                 Console.Error.WriteLine ("Couldn't reflect informations.");
290                                                 return 1;
291                                         }
292                                 } else {
293                                         Console.Error.WriteLine ("Couldn't load assembly '{0}'.", assemblyName);
294                                         return 2;
295                                 }
296                                 tw.Close ();
297                         }
298                         catch (Exception e) {
299                                 Console.Error.WriteLine ("Error: " + e.ToString ());
300                                 Help ();
301                                 return 3;
302                         }
303                         return 0;
304                 }
305         }
306 }