Code Access Security - B

 

Lets first write the simplest console application a.cs in the directory c:\g5.

 

a.cs

using System.IO;

public class zzz

{

public static void Main()

{

System.Console.WriteLine("Start");

StreamReader s = new StreamReader("C:\\a.txt");

string s1 = s.ReadLine();

System.Console.WriteLine("End " + s1);

}

}

 

Start

End hell

 

The above program uses the StreamReader class to read a file whose name is passed in the constructor and using the ReadLine function to read a line of the file. This function returns in our case the first line of the file which is stored in variable s1 and also displayed.

 

All programs that we write are allowed to execute without any restrictions on them. Lets now add some rules to what our programs are allowed to do. Each time our code wants to access some resource, it must have permission to do so. A resource can be accessing a file, registry, event log anything.

 

We have a program called strong name or sn that is part of the security tools available with the .net framework. We will run this program so that it can create a public key, private key pair for us.

 

Sn –k a.snk

 

The –k option creates a file a.snk whose size is 596 bytes and is created in the current directory. We now need to add this public key into the a.exe file. We will use the C# compiler to do this job for us.

 

csc /keyfile:a.snk a.cs

 

We see no change in our program as it runs a usual, all that we have added using the /keyfile option is the public key in the file. When we install the .net framework we also install the .net 2.0 configuration manager which is a Microsoft Management Console snap in. All configurations look and feel the same way as Microsoft has clear cut rules on how they should be written. We click on menu start, programs, Administrative Tools. .net 2.0 configuration.

 

We first select the plus of my computer, then the plus of runtime security policy, plus of machine, plus of permissions sets where we see a list of all permissions. We click on this option permissions sets with the right mouse button and then choose menu option new to create a new permission set. For the name we write p1, for description we forgot and then click on the button next. At the next window which is where we supply the actual permissions that make up p1 we do nothing and click on the button finish.

 

Thus our permission set p1 is empty. We now click on the plus of Code Groups and right mouse button on All_Code. Here we again choose menu option new, and for the name we write c1 and keep the description blank and click on the button next. For the condition we choose strong name which opens up some more text boxes for us. We click on the button import and navigate to c:\g5 where we choose a.exe.

 

The public key text box gets filled up by a very large number and we click on next. Here we see a drop down list box which contains all the permissions that we have created. We choose our empty permission set p1. We click on button next followed by button finish. When we run the a.exe file, it runs as if nothing ever happened.

 

Even though we called our code group c1, the actual name is Copy of c1 and we choose with the right mouse button and then menu option properties. Here we select the first of the two check boxes, this policy level will only have permissions… We then click on ok and once again run the a.exe file.

 

This time we get a zillion errors one them saying that we have no IO  permissions and hence an exception gets thrown. All that we need to do is simply give our program a.exe read rights on the file c:\a.txt. We choose the permission p1 in the configuration  manager, right mouse button, chose first option change permissions, choose File IO from first pane and then click on button Add >>. Here we come into another dialog box where we write the name of file c:\a.txt in the first text box and select the check box read by clicking on it twice.

 

We click on the button OK and then Finish and run a.exe once again and all works well now as our e.exe has the File IO rights on a.txt. We go back to our code and change the name from a.txt to b.txt like

 

StreamReader s = new StreamReader("C:\\b.txt");

 

We get the same exception thrown as our assembly has no rights on the file b.txt. We add this file as the second entry in the File IO permissions for p1 and the exception vanishes. We choose p1, right mouse button, Change permissions and then at the dialog box choose File IO in the right pane and then choose button properties. Now our code can access two file a.txt and b.txt.

 

using System.IO;

using System.Security.Permissions;

[assembly: FileIOPermission(SecurityAction.RequestMinimum,Read = @"C:\c.txt")]

public class zzz

{

public static void Main()

{

System.Console.WriteLine("Start");

StreamReader s = new StreamReader("C:\\c.txt");

string s1 = s.ReadLine();

System.Console.WriteLine("End " + s1);

}

}

 

The problem with the example earlier was that our WriteLine function gets called and then we see the exception. This could get pretty unnerving for the user where he is working on something and in the middle he gets an exception thrown at him. What we should do is before our program can start, someone should check for all permissions that we require and throw an exception at the start if we do have the required permissions.

 

We use the attribute FileIOPermission from the System.Security.Permissions namespace. The only problem is that this attribute cannot be used on types and methods so we preface it with assembly:, so that the attribute  is used not on the type zzz but on the assembly. The enum RequestMinimum from the  type SecurityMinimum does what the name specifies, what follows is the minimum permissions that we require. The only permission we require is Read rights on the file c.txt.

 

When we run the above program, we see no output of the WriteLine function displayed at all only an exception This is because before a single line of our code can get called, the system checks whether our assembly has the permissions that the attributes demand. As our attribute requires read rights on c:\c.txt, our assembly does not have such a right, we get an exception thrown but no code from our side gets called.

 

We go back to permission p1 and change the properties of the IO permission by adding c.txt to the two files already present. Now our program runs as normal.

 

[assembly: FileIOPermission(SecurityAction.RequestMinimum,Read = @"C:\c.txt")]

[assembly: FileIOPermission(SecurityAction.RequestMinimum,Read = @"C:\d.txt")]

public class zzz

 

We can specify the attributes as many times as we like and we will get an error as we have no read rights on file d.txt.

 

using System.Windows.Forms;

public class zzz :Form

{

public static void Main()

{

Application.Run(new zzz());

}

}

 

So far we worked with Console Applications, the above is a simple windows application. When we run it we get an error say that we have no user interface permissions. We go back to our permission p1, right mouse button, change permissions, and then choose User Interface from the left pane and click on button Add >>. At the dialog box the first lox box has the option No Windows, we choose the option Safe top level windows. We click on button OK and then button finish and run our program a.exe.

 

We see a nice window and a message from Microsoft that our application has security associated with it. Lets now add a button and some code that gets called when we click on the button.

 

using System.Windows.Forms;

using System.Drawing;

using System.IO;

public class zzz :Form

{

Button b;

TextBox t;

public static void Main()

{

Application.Run(new zzz());

}

public zzz()

{

b = new Button();

t = new TextBox();

b.Location = new Point(78, 59);

b.Text = "Click";

b.Click += new System.EventHandler(abc);

Controls.Add(b);

Controls.Add(t);

}

private void abc(object o, System.EventArgs e)

{

StreamReader f = new StreamReader(t.Text);

b.Text = f.ReadLine();

}

}

 

Most of the above program is placing a button and textbox on the screen. We write something in the textbox and then click on the button which calls the abc function. Here we open the file for reading and store the first line as the text of the button. If we write any of the three file names a, b and c.txt we get the button contents change, anything else and a exception gets thrown. This can get unnerving for a first time user and hence we must handle the exceptions ourselves.

 

private void abc(object o, System.EventArgs e)

{

try

{

StreamReader f = new StreamReader(t.Text);

b.Text = f.ReadLine();

}

catch (System.Exception ee)

{

MessageBox.Show(ee.Message);

}

}

 

We now simply add a try and catch to our code and type in d.txt. We now see our message box telling us of an error. We click on ok and are allowed to type another file name. More graceful.

 

private void abc(object o, System.EventArgs e)

{

try

{

string s = Environment.GetEnvironmentVariable("PATH");

MessageBox.Show(s);

}

catch (System.Exception ee)

{

MessageBox.Show(ee.Message);

}

}

 

We now try and read the value of the Environment variable PATH and then display it in a MessageBox. We use the static function GetEnvironmentVariable passing it the name of the variable to read. When we run the program we get an error as we have no permission to read this resource.

 

We go back to our permission p1 and choose Environment Variables in the first pane and then click on Add >>. In the dialog box we write the name of the environment variable Path and then select the check box under read. The other check box is if we want to write or change the value. We click on OK and Finish and our program now works like a charm.

 

[System.STAThread]

public static void Main()

{

Application.Run(new zzz());

}

 

private void abc(object o, System.EventArgs e)

{

try

{

OpenFileDialog f = new OpenFileDialog();

f.ShowDialog();

MessageBox.Show(f.FileName);

}

catch (System.Exception ee)

{

MessageBox.Show(ee.Message);

}

}

 

We first added the attribute STAThread where STA stands for Single Thread Apartment as we are using OLE calls. We create a instance of the OpenFileDialog class and then call ShowDialog to display the dialog box. Instead of seeing the dialog box we get an exception thrown at us as we do not have permissions to use file dialog boxes.

 

We once go to the p1 permission set and choose File Dialog in the first pane and then click on button Add>>. We have only two types of dialog boxes Open and Save. The default is none and we choose Open. We click on OK and then finish and now when we run our program does not work as advertised. We see the dialog box but when we choose any file including a.txt and click on Ok we get an exception thrown.

 

This is because we need to give all IO rights Read, Write Append and Directory to  the files or else we get an error. Thus we go back to the IO permissions of p1 and select all four check boxes.

 

As an exercise use the same permission class as an attribute so that no code of ours gets called until we have all the required permissions.