Re: Any good examples of modifying the CAS during install?



hi,

overwrite the install/uninstall methods to add custom actions...the following code should get you started

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;

using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
using System.Net;
using System.Data.SqlClient;

[RunInstaller(true)]
public class MyInstaller : System.Configuration.Install.Installer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

string permissionSetName = "Acme Permissions";
string permissionSetDesc = "This is the set of permissions needed by ..NET applications for Acme corporation";
string codeGroupName = "Acme Code Group";
string codeGroupDesc = "Grants a few extra permissions to any assembly signed with the Acme strong name";

public MyInstaller()
{
// This call is required by the Designer.
InitializeComponent();
}

#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion

// this code will run when the MSI file is installed
public override void Install(IDictionary stateSaver) {
// first need to find the machine policy,
// which is where we'll make our changes
PolicyLevel machinePolicy = _findPolicyLevel("Machine");

if (null == machinePolicy) {
// sanity check - this should never happen
throw new ApplicationException("Failed to find the machine policy in the PolicyHierarchy");
}

// we need to add a named permission set
// that includes whatever permissions we're granting
NamedPermissionSet nps = new NamedPermissionSet(permissionSetName, PermissionState.None);
nps.Description = permissionSetDesc;

// TODO: add the permissions AcmeExpense needs
nps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, @"c:\acme\expenses"));
nps.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read, "EXPENSE"));
nps.AddPermission(new SqlClientPermission(PermissionState.Unrestricted));
nps.AddPermission(new DataProtectionPermission(PermissionState.Unrestricted));

// add our named permission set to the machine policy level
// note that nothing is saved yet (we'll save at the end)
try {
machinePolicy.AddNamedPermissionSet(nps);
}
catch {
// duplicate name - update the existing one with the same name
machinePolicy.ChangeNamedPermissionSet(nps.Name, nps);
}

// now we need to create a code group that matches all assemblies
// that we ship with AcmeExpense - one way of doing this is to
// match the strong name we assign to that application (although
// depending on how you manage strong names, this might cover
// a wider set of assemblies)
CodeGroup cg = new UnionCodeGroup(
new StrongNameMembershipCondition(
new StrongNamePublicKeyBlob(acmePublicKey),
null, // match regardless of assembly's simple name
null), // match regardless of assembly's version
new PolicyStatement(nps,
PolicyStatementAttribute.Nothing) // no LevelFinal or Exclusive attribute on this code group
);
cg.Name = codeGroupName;
cg.Description = codeGroupDesc;

// code groups with duplicate names are legal, but messy and confusing,
// so we make sure to first remove any existing code groups with our name
_removeCodeGroupsByName(machinePolicy.RootCodeGroup, cg.Name);
// add our new code group (note we've not saved yet).
machinePolicy.RootCodeGroup.AddChild(cg);

// finally, save all changes atomically.
SecurityManager.SavePolicyLevel(machinePolicy);
}

// this code will run when our MSI is uninstalled
public override void Uninstall(System.Collections.IDictionary savedState) {
// first need to find the machine policy,
// which is where we'll make our changes
PolicyLevel machinePolicy = _findPolicyLevel("Machine");

if (null == machinePolicy) {
// sanity check - this should never happen
throw new ApplicationException("Failed to find the machine policy in the PolicyHierarchy");
}
// remove our code group
_removeCodeGroupsByName(machinePolicy.RootCodeGroup, codeGroupName);

// remove our named permission set
try {
machinePolicy.RemoveNamedPermissionSet(permissionSetName);
}
catch {
// if it's not there, no biggie - just doing our best to clean up.
}

// finally, save all changes atomically.
SecurityManager.SavePolicyLevel(machinePolicy);
}

PolicyLevel _findPolicyLevel(string labelWeWant) {
IEnumerator policyLevelEnumerator = SecurityManager.PolicyHierarchy();
PolicyLevel found = null;
while (policyLevelEnumerator.MoveNext()) {
PolicyLevel lvl = (PolicyLevel)policyLevelEnumerator.Current;
if (labelWeWant == lvl.Label) {
found = lvl;
}
}
return found;
}

void _removeCodeGroupsByName(CodeGroup parent, string childName) {
// the implementation of CodeGroup.Children (viewed with Anakrino)
// gives a deep copy of the children, so technically this is overkill,
// but the documentation doesn't guarantee this, so we enumerate
// then delete in two separate steps as you would with any dynamic list
ArrayList codeGroupsToRemove = new ArrayList();
foreach (CodeGroup existingCodeGroup in parent.Children) {
if (childName == existingCodeGroup.Name) {
codeGroupsToRemove.Add(existingCodeGroup);
}
}
foreach (CodeGroup cg in codeGroupsToRemove) {
parent.RemoveChild(cg);
}
}

// TODO: get the public key from AcmeExpense.exe using the secutil tool
byte[] acmePublicKey = new byte[]{ 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0,
6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 85, 73, 181, 56, 224, 255, 198, 167, 151, 206, 111, 135,
63, 32, 172, 222, 77, 52, 224, 240, 213,
218, 202, 79, 18, 100, 175, 171, 17, 242,
83, 200, 243, 42, 105, 75, 231, 4, 81, 164, 11, 105, 39, 193, 38, 32, 161, 246,
131, 55, 86, 216, 252, 116, 204, 12, 60,
91, 125, 46, 230, 95, 108, 13, 161, 34, 69, 98, 191, 236, 147, 208, 59, 80, 172,
98, 1, 213, 167, 105, 180, 135, 22, 231,
69, 11, 55, 252, 224, 212, 219, 86, 112,
32, 92, 118, 40, 250, 51, 173, 23, 33, 77, 179, 133, 49, 197, 137, 174, 236, 57, 143, 37, 244, 251, 98, 178, 255, 175,
135, 107, 5, 168, 106, 175, 184, 116, 206 };
}


---------------------------------------
Dominick Baier - DevelopMentor
http://www.leastprivilege.com

I need to modify the .NET 2.0 CAS (create a code group, etc) in my
installer. I'm using VS.NET 2K5 and I can't seem to find a good
example that does this. I can barely understand the general flow.

This is what I understand:
1) I create something (a library?) that has a class (say
MyInstaller)
that derives from System.Configuration.Install.Installer.
2) I register for installation events. Makes sense.
3) ... ? I'm lost here
...
10) ... ? I create a custom action to run my installer?
Has anyone done this? Are there any good examples?

Thanks

Gary F




.



Relevant Pages

  • Re: Hosted WinForms Controls and CAS
    ... this is part of an msi installer project - and should get you started... ... throw new ApplicationException("Failed to find the machine policy in the PolicyHierarchy"); ... // that includes whatever permissions we're granting ... CodeGroup cg = new UnionCodeGroup( ...
    (microsoft.public.dotnet.security)
  • Re: Hosted WinForms Controls and CAS
    ... this is part of an msi installer project - and should get you ... throw new ApplicationException("Failed to find the machine policy ... // that includes whatever permissions we're granting ... CodeGroup cg = new UnionCodeGroup( ...
    (microsoft.public.dotnet.security)
  • Question on PolicyLevel/PermissionSet/CodeGroups/SetAppDomainPolicy
    ... I'm applying certain permissions dynamically from an input for an AppDomain. ... What is the best way to override this permission with my own? ... another CodeGroup with some Membership condition and new ... a lower level. ...
    (microsoft.public.dotnet.security)