//-----------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace CustomActions{
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
internal sealed class CaspolSecurityPolicyCreator
{
#region Constructor/Destructor
private CaspolSecurityPolicyCreator() { }
#endregion
#region Methods
/// <summary>
/// AddSecurityPolicy
/// </summary>
/// <param name="machinePolicyLevel"></param>
/// <param name="solutionCodeGroupName"></param>
/// <param name="solutionCodeGroupDescription"></param>
/// <param name="assemblyPath"></param>
/// <param name="assemblyCodeGroupName"></param>
/// <param name="assemblyCodeGroupDescription"></param>
internal static void AddSecurityPolicy(
bool machinePolicyLevel,
string solutionCodeGroupName,
string solutionCodeGroupDescription,
string assemblyPath,
string assemblyCodeGroupName,
string assemblyCodeGroupDescription)
{
string frameworkFolder = GetFrameworkFolder();
string solutionInstallationLocation = Path.GetDirectoryName(assemblyPath);
string solutionInstallationUrl = Path.Combine(solutionInstallationLocation, "*");
string policyLevel;
string parentCodeGroup;
if (machinePolicyLevel)
{
policyLevel = "-m"; // Use Machine-level policy.
parentCodeGroup = "My_Computer_Zone"; // Use My_Computer_Zone for assemblies installed on the computer.
}
else
{
policyLevel = "-u"; // Use User-level policy.
parentCodeGroup = "All_Code";
}
// Add the solution code group. Grant no permission at this level.
string arguments = policyLevel + " -q -ag " + parentCodeGroup + " -url \"" + solutionInstallationUrl + "\" Nothing -n \"" + solutionCodeGroupName + "\" -d \"" + solutionCodeGroupDescription + "\"";
try
{
RunCaspolCommand(frameworkFolder, arguments);
}
catch (Exception ex)
{
string error = String.Format("Cannot create the security code group '{0}'.", solutionCodeGroupName);
throw new Exception(error, ex);
}
// Add the assembly code group. Grant FullTrust permissions to the main assembly.
try
{
// Use the assembly strong name as the membership condition.
// Ensure that the assembly is strong-named to give it full trust.
AssemblyName assemblyName = Assembly.LoadFile(assemblyPath).GetName();
arguments = policyLevel + " -q -ag \"" + solutionCodeGroupName + "\" -strong -file \"" + assemblyPath + "\" \"" + assemblyName.Name + "\" \"" + assemblyName.Version.ToString(4) + "\" FullTrust -n \"" + assemblyCodeGroupName + "\" -d \"" + assemblyCodeGroupDescription + "\"";
RunCaspolCommand(frameworkFolder, arguments);
}
catch (Exception ex)
{
try
{
// Clean the solutionCodeGroupName.
RemoveSecurityPolicy(machinePolicyLevel, solutionCodeGroupName);
}
catch {}
string error = String.Format("Cannot create the security code group '{0}'.", assemblyCodeGroupName);
throw new Exception(error, ex);
}
}///AddSecurityPolicy
/// <summary>
/// RemoveSecurityPolicy
/// </summary>
internal static void RemoveSecurityPolicy(
bool machinePolicyLevel,
string solutionCodeGroupName)
{
string frameworkFolder = GetFrameworkFolder();
string policyLevel;
if (machinePolicyLevel)
policyLevel = "-m"; // Use Machine-level policy.
else
policyLevel = "-u"; // Use User-level policy.
string arguments = policyLevel + " -q -rg \"" + solutionCodeGroupName + "\"";
RunCaspolCommand(frameworkFolder, arguments);
}//RemoveSecurityPolicy
/// <summary>
/// GetFrameworkFolder
/// </summary>
/// <returns></returns>
private static string GetFrameworkFolder()
{
// Get the targeted Framework folder.
Version version = new Version(2, 0, 50727);
return GetRuntimeInstallationDirectory(version, true);
}//GetFrameworkFolder
/// <summary>
/// RunCaspolCommand
/// </summary>
/// <param name="frameworkFolder"></param>
/// <param name="arguments"></param>
private static void RunCaspolCommand(string frameworkFolder, string arguments)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(Path.Combine(frameworkFolder, "caspol.exe"));
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.WorkingDirectory = frameworkFolder;
processStartInfo.Arguments = arguments;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
string caspolOutputMessage = process.StandardOutput.ReadToEnd();
process.WaitForExit();
int exitCode = 0;
if (process.HasExited)
exitCode = process.ExitCode;
if (exitCode != 0)
{
string message = null;
if (!String.IsNullOrEmpty(caspolOutputMessage))
{
String[] outputMessageLines = caspolOutputMessage.Split('\n');
for (int i = 2; i < outputMessageLines.Length; i++)
{
string line = outputMessageLines[i].Trim();
if (!String.IsNullOrEmpty(line))
{
message = line;
break;
}
}
}
if (String.IsNullOrEmpty(message))
message = "Cannot run the Code Access Security Policy tool (caspol.exe).";
throw new ApplicationException(message);
}
}//RunCaspolCommand
[Flags]
private enum RuntimeInfo : uint
{
UpgradeVersion = 0x1, // RUNTIME_INFO_UPGRADE_VERSION
RequestIA64 = 0x2, // RUNTIME_INFO_REQUEST_IA64
RequestAmd64 = 0x4, // RUNTIME_INFO_REQUEST_AMD64
RequestX86 = 0x8, // RUNTIME_INFO_REQUEST_X86
DoNotReturnDirectory = 0x10, // RUNTIME_INFO_DONT_RETURN_DIRECTORY
DoNotReturnVersion = 0x20, // RUNTIME_INFO_DONT_RETURN_VERSION
DoNotShowErrorDialog = 0x40 // RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG
}
[DllImport("mscoree.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = true, SetLastError = false)]
private static extern int /* [HRESULT] */ GetRequestedRuntimeInfo(
string /* [LPCWSTR] */ pExe,
string /* [LPCWSTR] */ pwszVersion,
string /* [LPCWSTR] */ pConfigurationFile,
uint /* [DWORD] */ startupFlags,
RuntimeInfo /* [DWORD] */ runtimeInfoFlags,
StringBuilder /* [LPWSTR] */ pDirectory,
uint /* [DWORD] */ dwDirectory,
out uint /* [DWORD *] */ dwDirectoryLength,
StringBuilder /* [LPWSTR] */ pVersion,
uint /* [DWORD] */ cchBuffer,
out uint /* [DWORD *] */ dwLength
);
/// <summary>
/// Returns the installation directory of the specified .NET runtime.
/// </summary>
/// <param name="version">
/// The version of the runtime.
/// </param>
/// <param name="upgradeVersion">
/// True to return the installation directory of the nearest compatible
/// runtime version, or false for an exact match.
/// </param>
/// <returns>
/// The .NET runtime installation directory.
/// </returns>
private static string GetRuntimeInstallationDirectory(Version version, bool upgradeVersion)
{
string versionString = "v" + version.ToString(3);
RuntimeInfo runtimeInfo = RuntimeInfo.DoNotShowErrorDialog;
if (upgradeVersion)
runtimeInfo |= RuntimeInfo.UpgradeVersion;
StringBuilder runtimeDirectory = new StringBuilder(270);
StringBuilder runtimeVersion = new StringBuilder("v65535.65535.65535".Length);
uint runtimeDirectoryLength;
uint runtimeVersionLength;
int errorCode = GetRequestedRuntimeInfo(null, versionString, null, 0, runtimeInfo, runtimeDirectory, (uint)runtimeDirectory.Capacity, out runtimeDirectoryLength, runtimeVersion, (uint)runtimeVersion.Capacity, out runtimeVersionLength);
Marshal.ThrowExceptionForHR(errorCode);
return Path.Combine(runtimeDirectory.ToString(), runtimeVersion.ToString());
}//GetRuntimeInstallationDirectory
#endregion
}
}
|