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