[gacutil] Use IKVM.Reflection instead of System.Reflection (#3582)
[mono.git] / mcs / tools / security / caspol.cs
1 //
2 // caspol.cs: Code Access Security Policy Tool
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2004 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.Cryptography;
16 using System.Security.Cryptography.X509Certificates;
17 using System.Security.Permissions;
18 using System.Security.Policy;
19 using System.Text;
20
21 using Mono.Security.Cryptography;
22
23 [assembly: AssemblyTitle ("Mono CasPol")]
24 [assembly: AssemblyDescription ("Command line tool to modify Code Access Security policies.")]
25
26 namespace Mono.Tools {
27
28         class CustomMembershipCondition : IMembershipCondition {
29
30                 SecurityElement _se;
31
32                 public CustomMembershipCondition (SecurityElement se)
33                 {
34                         _se = se;
35                 }
36
37                 public bool Check (Evidence evidence)
38                 {
39                         return true;
40                 }
41
42                 public IMembershipCondition Copy ()
43                 {
44                         return new CustomMembershipCondition (_se);
45                 }
46
47                 public void FromXml (SecurityElement e)
48                 {
49                         _se = e;
50                 }
51
52                 public SecurityElement ToXml ()
53                 {
54                         return _se;
55                 }
56
57                 public void FromXml (SecurityElement e, PolicyLevel level)
58                 {
59                         _se = e;
60                 }
61
62                 public SecurityElement ToXml (PolicyLevel level)
63                 {
64                         return _se;
65                 }
66         }
67
68         class CasPol {
69
70                 static ArrayList _levels;
71
72                 static private void Help () 
73                 {
74                         Console.WriteLine ("Usage: caspol [options] [arguments] ...{0}", Environment.NewLine);
75                 }
76
77                 // (to be) Stored Options
78                 static bool PolicyChangesConfirmation = true;
79
80                 static bool forcePolicyChanges = false;
81                 static bool policyLevelDefault = true;
82
83                 static void PrintGlobalInfo ()
84                 {
85                         Console.WriteLine ("Security: {0}", SecurityManager.SecurityEnabled);
86                         Console.WriteLine ("Execution check: {0}", SecurityManager.CheckExecutionRights);
87                         Console.WriteLine ("Policy changes confirmation: {0}", PolicyChangesConfirmation);
88                 }
89
90                 static bool Confirm ()
91                 {
92                         if (PolicyChangesConfirmation) {
93                                 Console.WriteLine ("WARNING: This action will modify the specified security policy!");
94                                 Console.WriteLine ("Do you want to change the policy ?");
95                                 string answer = Console.ReadLine ();
96                                 switch (answer.ToUpper ()) {
97                                 case "YES":
98                                 case "Y":
99                                         return true;
100                                 default:
101                                         Console.WriteLine ("Change aborted!");
102                                         return false;
103                                 }
104                         }
105                         return true;
106                 }
107
108                 static string Policies (string prefix)
109                 {
110                         StringBuilder sb = new StringBuilder (prefix);
111                         PolicyLevel pl = null;
112                         for (int i = 0; i < Levels.Count - 1; i++) {
113                                 pl = (PolicyLevel)Levels [i];
114                                 sb.AppendFormat ("{0}, ", pl.Label);
115                         }
116                         pl = (PolicyLevel)Levels [Levels.Count - 1];
117                         sb.Append (pl.Label);
118
119                         sb.Append (" policy level");
120                         if (Levels.Count > 1)
121                                 sb.Append ("s");
122
123                         return sb.ToString ();
124                 }
125
126                 // In Fx 1.0/1.1 there is not direct way to load a XML file 
127                 // into a SecurityElement so we use SecurityParser from 
128                 // Mono.Security.dll.
129                 static SecurityElement LoadXml (string filename)
130                 {
131                         if (!File.Exists (filename)) {
132                                 Console.WriteLine ("Couldn't not find '{0}'.", filename);
133                                 return null;
134                         }
135
136                         string xml = null;
137                         using (StreamReader sr = new StreamReader (filename)) {
138                                 xml = sr.ReadToEnd ();
139                                 sr.Close ();
140                         }
141                         // actually this use the SecurityParser (on the Mono 
142                         // runtime) in corlib do to the job - but it remove 
143                         // the dependency on Mono.Security.dll
144                         SecurityElement se = SecurityElement.FromString (xml);
145                         return se;
146                 }
147
148                 static PermissionSet LoadPermissions (string filename)
149                 {
150                         SecurityElement se = LoadXml (filename);
151                         if (se == null)
152                                 return null;
153
154                         PermissionSet ps = new PermissionSet (PermissionState.None);
155                         ps.FromXml (se);
156                         if (se.Attribute ("class").IndexOf ("System.Security.NamedPermissionSet") == -1)
157                                 return ps;
158                         // now we know it's a NamedPermissionSet
159                         return (PermissionSet) new NamedPermissionSet (se.Attribute ("Name"), ps);
160                 }
161
162                 static StrongName GetStrongName (string filename)
163                 {
164                         try {
165                                 AssemblyName an = AssemblyName.GetAssemblyName (filename);
166                                 byte [] pk = an.GetPublicKey ();
167                                 return new StrongName (new StrongNamePublicKeyBlob (pk), an.Name, an.Version);
168                         }
169                         catch (FileNotFoundException) {
170                                 Console.WriteLine ("Couldn't find assembly '{0}'.", filename);
171                                 return null;
172                         }
173                 }
174
175                 static Assembly GetAssembly (string filename)
176                 {
177                         try {
178                                 AssemblyName an = AssemblyName.GetAssemblyName (filename);
179                                 return Assembly.Load (an);
180                         }
181                         catch (FileNotFoundException) {
182                                 Console.WriteLine ("Couldn't find assembly '{0}'.", filename);
183                                 return null;
184                         }
185                 }
186
187                 static Evidence GetAssemblyEvidences (string filename)
188                 {
189                         return GetAssembly (filename).Evidence;
190                 }
191
192                 static bool OnOff (string value, ref bool on)
193                 {
194                         switch (value.ToUpper ()) {
195                         case "ON":
196                                 on = true;
197                                 break;
198                         case "OFF":
199                                 on = false;
200                                 break;
201                         default:
202                                 return false;
203                         }
204                         return true;
205                 }
206
207                 static bool SaveSettings ()
208                 {
209                         Console.WriteLine ("TODO - where to save those settings ?");
210                         return false;
211                 }
212
213
214                 // Actions
215
216                 static void ShowCodeGroup (CodeGroup cg, string prefix) 
217                 {
218                         Console.WriteLine ("{0}. {1}: {2}", prefix, cg.MembershipCondition, cg.PermissionSetName);
219                         for (int i=0; i < cg.Children.Count; i++) {
220                                 ShowCodeGroup ((CodeGroup)cg.Children [i], "  " + prefix + "." + (i + 1));
221                         }
222                 }
223
224                 // -lg
225                 // -listgroups
226                 static void ListCodeGroups ()
227                 {
228                         PrintGlobalInfo ();
229
230                         foreach (PolicyLevel pl in Levels) {
231                                 Console.WriteLine ("{0}Level: {1}{0}", Environment.NewLine, pl.Label);
232
233                                 Console.WriteLine ("Code Groups:{0}", Environment.NewLine);
234                                 ShowCodeGroup (pl.RootCodeGroup, "1");
235                         }
236                 }
237
238                 static void ShowDescription (CodeGroup cg, string prefix)
239                 {
240                         Console.WriteLine ("{0}. {1}: {2}", prefix, cg.Name, cg.Description);
241                         for (int i = 0; i < cg.Children.Count; i++) {
242                                 ShowDescription ((CodeGroup)cg.Children [i], "  " + prefix + "." + (i + 1));
243                         }
244                 }
245
246                 // -ld
247                 // -listdescription
248                 static void ListDescriptions ()
249                 {
250                         PrintGlobalInfo ();
251
252                         foreach (PolicyLevel pl in Levels) {
253                                 Console.WriteLine ("{0}Level: {1}{0}", Environment.NewLine, pl.Label);
254
255                                 Console.WriteLine ("Code Groups:{0}", Environment.NewLine);
256                                 ShowDescription (pl.RootCodeGroup, "1");
257                         }
258                 }
259
260                 // -lp
261                 // -listpset
262                 static void ListPermissionSets ()
263                 {
264                         PrintGlobalInfo ();
265
266                         foreach (PolicyLevel pl in Levels) {
267                                 Console.WriteLine ("{0}Level: {1}{0}", Environment.NewLine, pl.Label);
268
269                                 Console.WriteLine ("Named Permission Sets:{0}", Environment.NewLine);
270                                 int n=1;
271                                 foreach (NamedPermissionSet nps in pl.NamedPermissionSets) {
272                                         Console.WriteLine ("{0}. {1} ({2}) = {3}{4}", 
273                                                 n++, nps.Name, nps.Description, Environment.NewLine, nps);
274                                 }
275                         }
276                 }
277
278                 // -lf
279                 // -listfulltrust
280                 static void ListFullTrust ()
281                 {
282                         PrintGlobalInfo ();
283
284                         foreach (PolicyLevel pl in Levels) {
285                                 Console.WriteLine ("{0}Level: {1}{0}", Environment.NewLine, pl.Label);
286
287                                 Console.WriteLine ("Full Trust Assemblies:{0}", Environment.NewLine);
288                                 int n = 1;
289                                 foreach (StrongNameMembershipCondition snmc in pl.FullTrustAssemblies) {
290                                         Console.WriteLine ("{0}. {1} = {2}{3}",
291                                                 n++, snmc.Name, Environment.NewLine, snmc);
292                                 }
293                         }
294                 }
295
296                 static void ShowResolveGroup (PolicyLevel pl, Evidence e)
297                 {
298                         Console.WriteLine ("{0}Level: {1}{0}", Environment.NewLine, pl.Label);
299                         CodeGroup cg = pl.ResolveMatchingCodeGroups (e);
300                         Console.WriteLine ("Code Groups:{0}", Environment.NewLine);
301                         ShowCodeGroup (cg, "1");
302                         Console.WriteLine ();
303                 }
304
305                 // -rsg assemblyname
306                 // -resolvegroup assemblyname
307                 static bool ResolveGroup (string assemblyname)
308                 {
309                         Evidence ev = GetAssemblyEvidences (assemblyname);
310                         if (ev == null)
311                                 return false;
312
313                         if (policyLevelDefault) {
314                                 // different "default" here
315                                 IEnumerator e = SecurityManager.PolicyHierarchy ();
316                                 while (e.MoveNext ()) {
317                                         PolicyLevel pl = (PolicyLevel)e.Current;
318                                         ShowResolveGroup (pl, ev);
319                                 }
320                         } else {
321                                 // use the user specified levels
322                                 foreach (PolicyLevel pl in Levels) {
323                                         ShowResolveGroup (pl, ev);
324                                 }
325                         }
326                         return true;
327                 }
328
329                 // -rsp assemblyname
330                 // -resolveperm assemblyname
331                 static bool ResolvePermissions (string assemblyname)
332                 {
333                         Evidence ev = GetAssemblyEvidences (assemblyname);
334                         if (ev == null)
335                                 return false;
336
337                         PermissionSet ps = null;
338                         Console.WriteLine ();
339                         if (policyLevelDefault) {
340                                 // different "default" here
341                                 IEnumerator e = SecurityManager.PolicyHierarchy ();
342                                 while (e.MoveNext ()) {
343                                         PolicyLevel pl = (PolicyLevel)e.Current;
344                                         Console.WriteLine ("Resolving {0} level", pl.Label);
345                                         if (ps == null)
346                                                 ps = pl.Resolve (ev).PermissionSet;
347                                         else
348                                                 ps = ps.Intersect (pl.Resolve (ev).PermissionSet);
349                                 }
350                         } else {
351                                 // use the user specified levels
352                                 foreach (PolicyLevel pl in Levels) {
353                                         Console.WriteLine ("Resolving {0} level", pl.Label);
354                                         if (ps == null)
355                                                 ps = pl.Resolve (ev).PermissionSet;
356                                         else
357                                                 ps = ps.Intersect (pl.Resolve (ev).PermissionSet);
358                                 }
359                         }
360                         if (ps == null)
361                                 return false;
362
363                         IEnumerator ee = ev.GetHostEnumerator ();
364                         while (ee.MoveNext ()) {
365                                 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
366                                 if (ipf != null) {
367                                         IPermission p = ipf.CreateIdentityPermission (ev);
368                                         ps.AddPermission (p);
369                                 }
370                         }
371
372                         Console.WriteLine ("{0}Grant:{0}{1}", Environment.NewLine, ps.ToXml ().ToString ());
373                         return true;
374                 }
375
376                 // -ap namedxmlfile
377                 // -addpset namedxmlfile
378                 // -ap xmlfile name
379                 // -addpset xmlfile name
380                 static bool AddPermissionSet (string [] args, ref int i)
381                 {
382                         // two syntax - so we first load the XML file and
383                         // if it's not a named XML file, then we use the next 
384                         // parameter as it's name
385                         string xmlfile = args [++i];
386                         PermissionSet ps = LoadPermissions (xmlfile);
387                         if ((ps == null) || !Confirm ())
388                                 return false;
389
390                         NamedPermissionSet nps = null;
391                         if (ps is NamedPermissionSet) {
392                                 nps = (NamedPermissionSet)ps;
393                         } else {
394                                 nps = new NamedPermissionSet (args [++i], ps);
395                         }
396
397                         foreach (PolicyLevel pl in Levels) {
398                                 pl.AddNamedPermissionSet (nps);
399                                 SecurityManager.SavePolicyLevel (pl);
400                         }
401                         return true;
402                 }
403
404                 // -cp xmlfile psetname
405                 // -chgpset xmlfile psetname
406                 static bool ChangePermissionSet (string[] args, ref int i)
407                 {
408                         string xmlfile = args [++i];
409                         PermissionSet ps = LoadPermissions (xmlfile);
410                         if (ps == null)
411                                 return false;
412
413                         bool confirmed = false;
414                         string psname = args [++i];
415
416                         foreach (PolicyLevel pl in Levels) {
417                                 if (pl.GetNamedPermissionSet (psname) == null) {
418                                         Console.WriteLine ("Couldn't find '{0}' permission set in policy.", psname);
419                                         return false;
420                                 } else if (confirmed || Confirm ()) {
421                                         confirmed = true; // only ask once
422                                         pl.ChangeNamedPermissionSet (psname, ps);
423                                         SecurityManager.SavePolicyLevel (pl);
424                                 } else
425                                         return false;
426                         }
427                         return true;
428                 }
429
430                 // -rp psetname
431                 // -rempset psetname
432                 static bool RemovePermissionSet (string psname)
433                 {
434                         bool confirmed = false;
435
436                         foreach (PolicyLevel pl in Levels) {
437                                 PermissionSet ps = pl.GetNamedPermissionSet (psname);
438                                 if (ps == null) {
439                                         Console.WriteLine ("Couldn't find '{0}' permission set in policy.", psname);
440                                         return false;
441                                 } else if (confirmed || Confirm ()) {
442                                         confirmed = true; // only ask once
443                                         pl.RemoveNamedPermissionSet (psname);
444                                         SecurityManager.SavePolicyLevel (pl);
445                                         Console.WriteLine ("Permission set '{0}' removed from policy.", psname);
446                                 } else
447                                         return false;
448                         }
449                         return true;
450                 }
451
452                 // -af assemblyname
453                 // -addfulltrust assemblyname
454                 static bool AddFullTrust (string aname)
455                 {
456                         StrongName sn = GetStrongName (aname);
457                         if ((sn == null) || !Confirm ())
458                                 return false;
459
460                         foreach (PolicyLevel pl in Levels) {
461                                 pl.AddFullTrustAssembly (sn);
462                         }
463                         return true;
464                 }
465
466                 // -rf assemblyname
467                 // -remfulltrust assemblyname
468                 static bool RemoveFullTrust (string aname)
469                 {
470                         StrongName sn = GetStrongName (aname);
471                         if ((sn == null) || !Confirm ())
472                                 return false;
473
474                         foreach (PolicyLevel pl in Levels) {
475                                 pl.RemoveFullTrustAssembly (sn);
476                         }
477                         return true;
478                 }
479
480
481                 static CodeGroup FindCodeGroupByName (string name, ref CodeGroup parent)
482                 {
483                         for (int i = 0; i < parent.Children.Count; i++) {
484                                 CodeGroup child = (CodeGroup)parent.Children [i];
485                                 if (child.Name == name) {
486                                         return child;
487                                 } else {
488                                         CodeGroup cg = FindCodeGroupByName (name, ref child);
489                                         if (cg != null)
490                                                 return cg;
491                                 }
492                         }
493                         return null;
494                 }
495
496                 static CodeGroup FindCodeGroupByLabel (string label, string current, ref CodeGroup parent)
497                 {
498                         for (int i=0; i < parent.Children.Count; i++) {
499                                 CodeGroup child = (CodeGroup)parent.Children [i];
500                                 string temp = String.Concat (current, ".", (i + 1).ToString ());
501                                 if ((label == temp) || (label == temp + ".")) {
502                                         return child;
503                                 } else if (label.StartsWith (temp)) {
504                                         CodeGroup cg = FindCodeGroupByLabel (label, temp, ref child);
505                                         if (cg != null)
506                                                 return cg;
507                                 }
508                         }
509                         return null;
510                 }
511
512                 static CodeGroup FindCodeGroup (string name, ref CodeGroup parent, ref PolicyLevel pl)
513                 {
514                         if (name.Length < 1)
515                                 return null;
516                         
517                         // Notes:
518                         // - labels starts with numbers (e.g. 1.2.1)
519                         // - names cannot start with numbers (A-Z, 0-9 and _)
520                         bool label = Char.IsDigit (name, 0);
521
522                         // More notes
523                         // - we can't remove the root code group
524                         // - we remove only one group (e.g. name)
525                         for (int i=0; i < Levels.Count; i++) {
526                                 pl = (PolicyLevel) Levels [i];
527                                 parent = pl.RootCodeGroup;
528                                 CodeGroup cg = null;
529                                 if (label)
530                                         cg = FindCodeGroupByLabel (name, "1", ref parent);
531                                 else
532                                         cg = FindCodeGroupByName (name, ref parent);
533                                 
534                                 if (cg != null)
535                                         return cg;
536                         }
537                         Console.WriteLine ("CodeGroup with {0} '{1}' was not found!",
538                                 label ? "label" : "name", name);
539                         return null;
540                 }
541
542                 // -custom xmlfile
543                 static IMembershipCondition ProcessCustomMembership (string filename)
544                 {
545                         SecurityElement se = LoadXml (filename);
546                         if (se == null)
547                                 return null;
548                         return new CustomMembershipCondition (se);
549                 }
550
551                 // -hash algo -hex hash
552                 // -hash algo -file assemblyname
553                 static IMembershipCondition ProcessHashMembership (string[] args, ref int i)
554                 {
555                         HashAlgorithm ha = HashAlgorithm.Create (args [++i]);
556                         byte [] value = null;
557                         switch (args [++i]) {
558                                 case "-hex":
559                                         value = CryptoConvert.FromHex (args [++i]);
560                                         break;
561                                 case "-file":
562                                         Hash hash = new Hash (GetAssembly (args [++i]));
563                                         value = hash.GenerateHash (ha);
564                                         break;
565                                 default:
566                                         return null;
567                         }
568                         return new HashMembershipCondition (ha, value);
569                 }
570
571                 // -pub -cert certificate
572                 // -pub -file signedfile
573                 // -pub -hex rawdata
574                 static IMembershipCondition ProcessPublisherMembership (string[] args, ref int i)
575                 {
576                         X509Certificate cert = null;
577                         switch (args [++i]) {
578                                 case "-cert":
579                                         cert = X509Certificate.CreateFromCertFile (args [++i]);
580                                         break;
581                                 case "-file":
582                                         cert = X509Certificate.CreateFromSignedFile (args [++i]);
583                                         break;
584                                 case "-hex":
585                                         byte[] raw = CryptoConvert.FromHex (args [++i]);
586                                         cert = new X509Certificate (raw);
587                                         break;
588                                 default:
589                                         return null;
590                         }
591                         return new PublisherMembershipCondition (cert);
592                 }
593
594                 // -strong -file filename [name | -noname] [version | -noversion]
595                 static IMembershipCondition ProcessStrongNameMembership (string[] args, ref int i)
596                 {
597                         if (args [++i] != "-file") {
598                                 Console.WriteLine ("Missing -file parameter.");
599                                 return null;
600                         }
601                         
602                         StrongName sn = GetStrongName (args [++i]);
603
604                         string name = args [++i];
605                         if (name == "-noname")
606                                 name = null;
607
608                         Version v = null;
609                         string version = args [++i];
610                         if (version != "-noversion")
611                                 v = new Version (version);
612
613                         return new StrongNameMembershipCondition (sn.PublicKey, name, v);
614                 }
615
616                 static bool ProcessCodeGroup (CodeGroup cg, string[] args, ref int i)
617                 {
618                         IMembershipCondition mship = null;
619                         for (; i < args.Length; i++) {
620                                 switch (args [++i]) {
621                                 case "-all":
622                                         cg.MembershipCondition = new AllMembershipCondition ();
623                                         break;
624                                 case "-appdir":
625                                         cg.MembershipCondition = new ApplicationDirectoryMembershipCondition ();
626                                         break;
627                                 case "-custom":
628                                         mship = ProcessCustomMembership (args [++i]);
629                                         if (mship == null)
630                                                 return false;
631                                         cg.MembershipCondition = mship;
632                                         break;
633                                 case "-hash":
634                                         mship = ProcessHashMembership (args, ref i);
635                                         if (mship == null)
636                                                 return false;
637                                         cg.MembershipCondition = mship;
638                                         break;
639                                 case "-pub":
640                                         mship = ProcessPublisherMembership (args, ref i);
641                                         if (mship == null)
642                                                 return false;
643                                         cg.MembershipCondition = mship;
644                                         break;
645                                 case "-site":
646                                         cg.MembershipCondition = new SiteMembershipCondition (args [++i]);
647                                         break;
648                                 case "-strong":
649                                         mship = ProcessStrongNameMembership (args, ref i);
650                                         if (mship == null)
651                                                 return false;
652                                         cg.MembershipCondition = mship;
653                                         break;
654                                 case "-url":
655                                         cg.MembershipCondition = new UrlMembershipCondition (args [++i]);
656                                         break;
657                                 case "-zone":
658                                         SecurityZone zone = (SecurityZone) Enum.Parse (typeof (SecurityZone), args [++i]);
659                                         cg.MembershipCondition = new ZoneMembershipCondition (zone);
660                                         break;
661
662                                 case "-d":
663                                 case "-description":
664                                         cg.Description = args [++i];
665                                         break;
666                                 case "-exclusive":
667                                         bool exclusive = false;
668                                         if (OnOff (args [++i], ref exclusive)) {
669                                                 if (exclusive)
670                                                         cg.PolicyStatement.Attributes |= PolicyStatementAttribute.Exclusive;
671                                         }
672                                         else
673                                                 return false;
674                                         break;
675                                 case "-levelfinal":
676                                         bool final = false;
677                                         if (OnOff (args [++i], ref final)) {
678                                                 if (final)
679                                                         cg.PolicyStatement.Attributes |= PolicyStatementAttribute.LevelFinal;
680                                         }
681                                         else
682                                                 return false;
683                                         break;
684                                 case "-n":
685                                 case "-name":
686                                         cg.Name = args [++i];
687                                         break;
688                                 default:
689                                         i--;
690                                         break;
691                                 }
692                         }
693                         return true;
694                 }
695
696                 // -ag label|name membership psetname flag
697                 // -addgroup label|name membership psetname flag
698                 static bool AddCodeGroup (string[] args, ref int i)
699                 {
700                         string name = args [++i];
701
702                         PolicyLevel pl = null;
703                         CodeGroup parent = null;
704                         CodeGroup cg = FindCodeGroup (name, ref parent, ref pl);
705                         if ((pl == null) || (parent == null) || (cg == null))
706                                 return false;
707
708                         UnionCodeGroup child = new UnionCodeGroup (
709                                 new AllMembershipCondition (), 
710                                 new PolicyStatement (new PermissionSet (PermissionState.Unrestricted)));
711                         if (!ProcessCodeGroup (child, args, ref i))
712                                 return false;
713
714                         cg.AddChild (child);
715                         SecurityManager.SavePolicyLevel (pl);
716                         Console.WriteLine ("CodeGroup '{0}' added in {1} policy level.",
717                                 cg.Name, pl.Label);
718                         return true;
719                 }
720
721                 // -cg label|name membership|psetname|flag
722                 // -chggroup label|name membership|psetname|flag
723                 static bool ChangeCodeGroup (string[] args, ref int i)
724                 {
725                         string name = args [++i];
726
727                         PolicyLevel pl = null;
728                         CodeGroup parent = null;
729                         CodeGroup cg = FindCodeGroup (name, ref parent, ref pl);
730                         if ((pl == null) || (parent == null) || (cg == null))
731                                 return false;
732
733                         if (!ProcessCodeGroup (cg, args, ref i))
734                                 return false;
735
736                         SecurityManager.SavePolicyLevel (pl);
737                         Console.WriteLine ("CodeGroup '{0}' modified in {1} policy level.",
738                                 cg.Name, pl.Label);
739                         return true;
740                 }
741
742                 // -rg label|name
743                 // -remgroup label|name
744                 static bool RemoveCodeGroup (string name)
745                 {
746                         PolicyLevel pl = null;
747                         CodeGroup parent = null;
748                         CodeGroup cg = FindCodeGroup (name, ref parent, ref pl);
749                         if ((pl == null) || (parent == null) || (cg == null))
750                                 return false;
751
752                         if (!Confirm ())
753                                 return false;
754
755                         parent.RemoveChild (cg);
756                         SecurityManager.SavePolicyLevel (pl);
757                         Console.WriteLine ("CodeGroup '{0}' removed from {1} policy level.",
758                                 cg.Name, pl.Label);
759                         return true;
760                 }
761
762                 // -r
763                 // -recover
764                 static void Recover ()
765                 {
766                         // no confirmation required to recover
767                         foreach (PolicyLevel pl in Levels) {
768                                 pl.Recover ();
769                                 SecurityManager.SavePolicyLevel (pl);
770                         }
771                 }
772
773                 // -rs
774                 // -reset
775                 static bool Reset ()
776                 {
777                         Console.WriteLine (Policies ("Resetting "));
778                         if (Confirm ()) {
779                                 foreach (PolicyLevel pl in Levels) {
780                                         pl.Reset ();
781                                         SecurityManager.SavePolicyLevel (pl);
782                                 }
783                                 return true;
784                         }
785                         return false;
786                 }
787
788                 // -s on|off
789                 // -security on|off
790                 static bool Security (string value)
791                 {
792                         bool on = true;
793                         if (!OnOff (value, ref on))
794                                 return false;
795                         SecurityManager.SecurityEnabled = on;
796                         return SaveSettings ();
797                 }
798
799                 // -e on|off
800                 // -execution on|off
801                 static bool Execution (string value)
802                 {
803                         bool on = true;
804                         if (!OnOff (value, ref on))
805                                 return false;
806                         SecurityManager.CheckExecutionRights = on;
807                         return SaveSettings ();
808                 }
809
810                 // -b
811                 // -buildcache
812                 static bool BuildCache ()
813                 {
814                         // TODO
815                         return false;
816                 }
817
818                 // -pp on|off
819                 // -polchgprompt on|off
820                 static bool PolicyChangePrompt (string value)
821                 {
822                         bool on = true;
823                         if (!OnOff (value, ref on))
824                                 return false;
825                         PolicyChangesConfirmation = on;
826                         return SaveSettings ();
827                 }
828
829
830                 // Policy Levels Internal Management
831
832                 static PolicyLevel levelEnterprise;
833                 static PolicyLevel levelMachine;
834                 static PolicyLevel levelUser;
835
836                 static void BuildLevels ()
837                 {
838                         IEnumerator e = SecurityManager.PolicyHierarchy ();
839                         if (e.MoveNext ())
840                                 levelEnterprise = (PolicyLevel) e.Current;
841                         if (e.MoveNext ())
842                                 levelMachine = (PolicyLevel) e.Current;
843                         if (e.MoveNext ())
844                                 levelUser = (PolicyLevel) e.Current;
845                 }
846
847                 static PolicyLevel Enterprise {
848                         get {
849                                 if (levelEnterprise == null)
850                                         BuildLevels ();
851                                 return levelEnterprise;
852                         }
853                 }
854
855                 static PolicyLevel Machine {
856                         get {
857                                 if (levelMachine == null)
858                                         BuildLevels ();
859                                 return levelMachine;
860                         }
861                 }
862
863                 static PolicyLevel User {
864                         get {
865                                 if (levelUser == null)
866                                         BuildLevels ();
867                                 return levelUser;
868                         }
869                 }
870
871                 static ArrayList Levels {
872                         get {
873                                 if (_levels == null)
874                                         _levels = new ArrayList (3);
875                                 return _levels;
876                         }
877                 }
878
879                 static bool ProcessInstruction (string[] args, ref int i)
880                 {
881                         for (; i < args.Length; i++) {
882                                 switch (args [i]) {
883                                 case "-q":
884                                 case "-quiet":
885                                         PolicyChangesConfirmation = false;
886                                         break;
887                                 case "-f":
888                                 case "-force":
889                                         forcePolicyChanges = true;
890                                         break;
891                                 case "-?":
892                                 case "/?":
893                                 case "-h":
894                                 case "-help":
895                                         Help ();
896                                         break;
897
898                                 case "-a":
899                                 case "-all":
900                                         policyLevelDefault = false;
901                                         Levels.Clear ();
902                                         Levels.Add (Enterprise);
903                                         Levels.Add (Machine);
904                                         Levels.Add (User);
905                                         break;
906                                 case "-ca":
907                                 case "-customall":
908                                         policyLevelDefault = false;
909                                         Levels.Clear ();
910                                         Levels.Add (Enterprise);
911                                         Levels.Add (Machine);
912                                         Levels.Add (SecurityManager.LoadPolicyLevelFromFile (args [++i], PolicyLevelType.User));
913                                         break;
914                                 case "-cu":
915                                 case "-customuser":
916                                         policyLevelDefault = false;
917                                         Levels.Clear ();
918                                         Levels.Add (SecurityManager.LoadPolicyLevelFromFile (args [++i], PolicyLevelType.User));
919                                         break;
920                                 case "-en":
921                                 case "-entreprise":
922                                         policyLevelDefault = false;
923                                         Levels.Clear ();
924                                         Levels.Add (Enterprise);
925                                         break;
926                                 case "-m":
927                                 case "-machine":
928                                         policyLevelDefault = false;
929                                         Levels.Clear ();
930                                         Levels.Add (Machine);
931                                         break;
932                                 case "-u":
933                                 case "-user":
934                                         policyLevelDefault = false;
935                                         Levels.Clear ();
936                                         Levels.Add (User);
937                                         break;
938
939                                 case "-lg":
940                                 case "-listgroups":
941                                         ListCodeGroups ();
942                                         break;
943                                 case "-ld":
944                                 case "-listdescription":
945                                         ListDescriptions ();
946                                         break;
947                                 case "-lp":
948                                 case "-listpset":
949                                         ListPermissionSets ();
950                                         break;
951                                 case "-lf":
952                                 case "-listfulltrust":
953                                         ListFullTrust ();
954                                         break;
955                                 case "-l":
956                                 case "-list":
957                                         ListCodeGroups ();
958                                         Console.WriteLine ();
959                                         ListPermissionSets ();
960                                         Console.WriteLine ();
961                                         ListFullTrust ();
962                                         break;
963
964                                 case "-rsg":
965                                 case "-resolvegroup":
966                                         if (!ResolveGroup (args [++i]))
967                                                 return false;
968                                         break;
969                                 case "-rsp":
970                                 case "-resolveperm":
971                                         if (!ResolvePermissions (args [++i]))
972                                                 return false;
973                                         break;
974
975                                 case "-ap":
976                                 case "-addpset":
977                                         if (!AddPermissionSet (args, ref i))
978                                                 return false;
979                                         break;
980                                 case "-cp":
981                                 case "-chgpset":
982                                         if (!ChangePermissionSet (args, ref i))
983                                                 return false;
984                                         break;
985                                 case "-rp":
986                                 case "-rempset":
987                                         if (!RemovePermissionSet (args [++i]))
988                                                 return false;
989                                         break;
990
991                                 case "-af":
992                                 case "-addfulltrust":
993                                         if (!AddFullTrust (args [++i]))
994                                                 return false;
995                                         break;
996                                 case "-rf":
997                                 case "-remfulltrust":
998                                         if (!RemoveFullTrust (args [++i]))
999                                                 return false;
1000                                         break;
1001
1002                                 case "-ag":
1003                                 case "-addgroup":
1004                                         if (!AddCodeGroup (args, ref i))
1005                                                 return false;
1006                                         break;
1007                                 case "-cg":
1008                                 case "-chggroup":
1009                                         if (!ChangeCodeGroup (args, ref i))
1010                                                 return false;
1011                                         break;
1012                                 case "-rg":
1013                                 case "-remgroup":
1014                                         if (!RemoveCodeGroup (args [++i]))
1015                                                 return false;
1016                                         break;
1017
1018                                 case "-r":
1019                                 case "-recover":
1020                                         Recover ();
1021                                         break;
1022                                 case "-rs":
1023                                 case "-reset":
1024                                         if (!Reset ())
1025                                                 return false;
1026                                         break;
1027
1028                                 case "-s":
1029                                 case "-security":
1030                                         if (!Security (args [++i]))
1031                                                 return false;
1032                                         break;
1033                                 case "-e":
1034                                 case "-execution":
1035                                         if (!Execution (args [++i]))
1036                                                 return false;
1037                                         break;
1038                                 case "-b":
1039                                 case "-buildcache":
1040                                         if (!BuildCache ())
1041                                                 return false;
1042                                         break;
1043                                 case "-pp":
1044                                 case "-polchgprompt":
1045                                         if (!PolicyChangePrompt (args [++i]))
1046                                                 return false;
1047                                         break;
1048
1049                                 default:
1050                                         Console.WriteLine ("*** unknown argument {0} ***", args [i]);
1051                                         return false;
1052                                 }
1053                                 Console.WriteLine ();
1054                         }
1055                         return true;
1056                 }
1057
1058                 static void SetDefaultPolicyLevel ()
1059                 {
1060                         // default is User for normal users and Machine for 
1061                         // administrators. Here we define an administrator as
1062                         // someone who can write to the Machine policy files
1063                         try {
1064                                 using (FileStream fs = File.OpenWrite (Machine.StoreLocation)) {
1065                                         fs.Close ();
1066                                 }
1067                                 Levels.Add (Machine);
1068                         }
1069                         catch {
1070                                 Levels.Add (User);
1071                         }
1072                         // some actions, like resolves, use a different default (all)
1073                         policyLevelDefault = true;
1074                 }
1075
1076                 [STAThread]
1077                 static int Main (string[] args) 
1078                 {
1079                         Console.WriteLine (new AssemblyInfo ().ToString ());
1080                         if (args.Length == 0) {
1081                                 Help ();
1082                                 return 0;
1083                         }
1084
1085                         try {
1086                                 // set default level (when none is specified 
1087                                 // by command line options)
1088                                 SetDefaultPolicyLevel ();
1089
1090                                 // process instructions (i.e. multiple 
1091                                 // instructions can be chained)
1092                                 for (int i=0; i < args.Length; i++) {
1093                                         if (!ProcessInstruction (args, ref i))
1094                                                 return 1;
1095                                 }
1096                         }
1097                         catch (Exception e) {
1098                                 Console.WriteLine ("Error: " + e.ToString ());
1099                                 Help ();
1100                                 return 2;
1101                         }
1102                         Console.WriteLine ("Success");
1103                         return 0;
1104                 }
1105         }
1106 }