Increasing Permissions
Although it's
There are a number of ways to increase permissions for an assembly. For example, if you're
Figure 15.6. Adjusting .NET Security
If you'd like to be a little less sweeping in your security changes (a practice I heartily recommend), you can use the Internet Control Panel to configure your system to trust all assemblies from a specific site, as shown in Figure 15.7. Figure 15.7. Using the Internet Control Panel to Add Trusted Sites
Any sites listed as trusted in the Internet Control Panel settings are awarded Internet permissions. If this is still too broad, you can be even more
If you'd like to adjust permission for a specific assembly, you can set up a custom code group using the Microsoft .NET Framework Configuration tool, or you can use the Trust an Assembly Wizard. This tool creates a code
http://trustedmachine/hr452/hr452.exe Based on that URL, you'll be asked whether you'd like to trust only this assembly, all assemblies from the same publisher, or all of the assemblies having the same public key. To simplify security configuration, it's a good idea to sign all your assemblies with the same public/private key pair. For example, I signed both wahoo.exe and wahooControl.dll and can adjust both of their permissions at once by choosing to trust assemblies having the same key, as shown in Figure 15.8. Figure 15.8. Trusting All Assemblies Having the Same Public Key
Here I've set all assemblies having the same public key, regardless of version, to be trusted. This is a good policy because it allows an entire family of trusted applications to be trusted with a single code group.
After you've specified which assemblies to trust in the Trust an Assembly Wizard, you'll be asked how much trust you'd like them to have on a sliding scale. It's hard to tell from the
Figure 15.9. How Much an Assembly Is Trusted
With the new code group in place, the
Awarding permissions to your own assemblies is a matter of creating a code group with a membership condition that matches your assemblies ”which site it came from, which URL it came from, which key it's signed with, and so on ”and matching it to a set of permissions.
Furthermore, you can build your own custom permission set or use one of the default permission sets. Deciding whether to build your own custom permission set is a matter of being familiar with the built-in permission sets, although creating a new one that overlaps with a built-in one won't hurt
However, if you need access to any assemblies not marked with APTCA, then you'll need to create a code group that awards your assembly the FullTrust permission set. None of the other default named permission sets, even the Everything permission set, can award permissions to access assemblies not
Increasing Permissions Programmatically
As facile as you may become with the .NET permission policy administration tools, you never want to wander to each of your
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
// Generated with 'secutil -c -s wahoo.exe'
byte[] publicKey = { 0, 36, ... };
// Find the machine policy level
PolicyLevel machinePolicyLevel = null;
System.Collections.IEnumerator ph =
SecurityManager.PolicyHierarchy();
while( ph.MoveNext() ) {
PolicyLevel pl = (PolicyLevel)ph.Current;
if( pl.Label == "Machine" ) {
machinePolicyLevel = pl;
break;
}
}
if( machinePolicyLevel == null ) return;
// Create a new code group giving Wahoo! Internet permissions
PermissionSet permSet1 = new NamedPermissionSet("Internet");
StrongNamePublicKeyBlob key = new StrongNamePublicKeyBlob(publicKey);
IMembershipCondition membership1 =
new StrongNameMembershipCondition(key, null, null);
// Create the code group
PolicyStatement policy1 = new PolicyStatement(permSet1);
CodeGroup codeGroup1 = new UnionCodeGroup(membership1, policy1);
codeGroup1.Description =
"Internet permissions for Sells Brothers Wahoo!";
codeGroup1.Name = "Sells Brothers Wahoo!";
// Add the code group
machinePolicyLevel.RootCodeGroup.AddChild(codeGroup1);
// Create a new code group giving all of
// sellsbrothers.com Execute permission
PermissionSet permSet2 = new NamedPermissionSet("Execution");
IMembershipCondition membership2 =
new SiteMembershipCondition("www.sellsbrothers.com");
// Create the code group
PolicyStatement policy2 = new PolicyStatement(permSet2);
CodeGroup codeGroup2 = new UnionCodeGroup(membership2, policy2);
codeGroup2.Description =
"Minimal execute permissions for sellsbrothers.com";
codeGroup2.Name = "sellsbrothers.com minimal execute";
// Add the code group
machinePolicyLevel.RootCodeGroup.AddChild(codeGroup2);
// Save changes
SecurityManager.SavePolicy();
This code actually adds two code groups: one to award Internet permissions to all assemblies signed with a known strong name, and a second one to work around an "issue" that emerged in .NET 1.0 SP1 whereby a site as a whole must have at least Execute permission for any other permissions awarded a strong name to take effect. We start by using SecurityManager to find the top of the Machine runtime policy hierarchy, where we'll add the new code groups. We then grab the Internet NamedPermissionSet and join it with StrongNameMembershipCondition to produce the new code group. We then name the new code group something that'll make sense in the administration tools and add it to the root code group along with all the existing code groups. (If we had wanted to award our assemblies full trust, we'd have passed the string "FullTrust" instead of "Internet" when creating this NamedPermissionSet object.) After creating the first permission set, we do the same thing again with the Execution NamedPermissionSet and the SiteMembershipCondition, naming them and adding them as well. To commit the changes to the Machine runtime security policy, we ask SecurityManager to save, and that's it. This code is all that's necessary to award permissions from existing permission sets to your assemblies. If you want to create a custom permission set, the code is similar except that you create an instance of an empty NamedPermissionSet object and add permission objects that derive from CodeAccessPermission, such as FileIOPermission and DirectoryServicesPermission. You then add new permission sets to the machine policy via the AddNamedPermissionSet method:
// Create a named, empty permission set
NamedPermissionSet permSet =
new NamedPermissionSet("My Permission Set", PermissionState.None);
// Add a permission
IPermission perm = new DirectoryServicesPermission();
permSet.AddPermission(perm);
machinePolicyLevel.AddNamedPermissionSet(permSet);
Notice the use of PermissionState.None passed to the NamedPermissionSet constructor. Without that, you get a permission set just like FullTrust, with all permissions. Instead, you want an empty permission set that has only those permissions that you explicitly add. Deploying PermissionsAfter you've got managed code to award permissions, it needs to run on the machine with FullTrust. Otherwise, it won't have permission to modify the permission policy (it must also be running as a Win32 Administrator). Placing an EXE on a Web server and asking users to click on a link won't do, because then the code will be in a partially trusted environment and we're back where we started.
The
There are many ways to build MSI files, but the most readily available one comes with advanced versions of VS.NET. The trick is to convince a setup project to execute your code during installation. Assuming you've got a VS.NET solution with a setup project and a class library project, you have only two major
The first task is to add a class to your class library project that derives from System.Configuration.Install.Installer and is tagged with the RunInstaller(true) attribute. An instance of any such class will be created by the MSI engine during setup, so that's where you put your custom code. The easiest way to get such a class is to right-click on your class library project in Solution Explorer and choose Add New Item Code Installer Class. It will create a place for your permission award code in the constructor: [RunInstaller(true)] public class Installer1 : System.Configuration.Install.Installer { public Installer1() { ... // TODO: Add your permission award code here } } Your second task is to add this assembly to the list of custom actions that your setup will perform during installation. To do that, right-click on your setup project in Solution Explorer and choose View Custom Actions. This will show you a list of the custom actions at each phase of the setup, as shown in Figure 15.10. Figure 15.10. Setup Project Custom Actions
To add a custom action to the install phase, right-click on the Install custom action list and choose Add Custom Action. This will show the list of folders to place your custom action code into, as shown in Figure 15.11. Figure 15.11. Choosing a Folder for a Custom Action
Double-click Application Folder and choose Add Output to choose the output from one of the other projects in the solution. Make sure the class library project with your installer class is selected at the top, and choose Primary Output, as shown in Figure 15.12. Figure 15.12. Choosing the Primary Output of Your Class Library Project to Act as a Custom Action
These settings will cause the installer classes in your class library assembly to be created during the Install phase of your MSI setup. Now, when you build and execute the MSI file produced by the setup project, your code will execute at FullTrust and can award permissions for your assemblies. |