MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4//5// Application white listing policies such as AppLocker and DeviceGuard UMCI are only implemented on Windows OSs6//7#if !UNIX8 9using System.Diagnostics;10using System.Diagnostics.CodeAnalysis;11using System.Management.Automation.Internal;12using System.Management.Automation.Runspaces;13using System.Management.Automation.Tracing;14using System.Runtime.InteropServices;15 16namespace System.Management.Automation.Security17{18 /// <summary>19 /// System wide policy enforcement for a specific script file.20 /// </summary>21 public enum SystemScriptFileEnforcement22 {23 /// <summary>24 /// No policy enforcement.25 /// </summary>26 None = 0,27 28 /// <summary>29 /// Script file is blocked from running.30 /// </summary>31 Block = 1,32 33 /// <summary>34 /// Script file is allowed to run without restrictions (FullLanguage mode).35 /// </summary>36 Allow = 2,37 38 /// <summary>39 /// Script file is allowed to run in ConstrainedLanguage mode only.40 /// </summary>41 AllowConstrained = 3,42 43 /// <summary>44 /// Script file is allowed to run in FullLanguage mode but will emit ConstrainedLanguage restriction audit logs.45 /// </summary>46 AllowConstrainedAudit = 447 }48 49 /// <summary>50 /// How the policy is being enforced.51 /// </summary>52 // Internal Note: Current code that consumes this enum assumes that anything but 'Enforce' means53 // that the script is allowed, and that a system lockdown policy that is anything but 'None' means54 // that the API should be called again for individual files. If any elements are added to this enum,55 // callers of the GetLockdownPolicy() should be reviewed.56 public enum SystemEnforcementMode57 {58 /// Not enforced at all59 None = 0,60 61 /// Enabled - allow, but audit62 Audit = 1,63 64 /// Enabled, enforce restrictions65 Enforce = 266 }67 68 /// <summary>69 /// Support class for dealing with the Windows Lockdown Policy,70 /// Device Guard, and Constrained PowerShell.71 /// </summary>72 public sealed class SystemPolicy73 {74 private SystemPolicy()75 {76 }77 78 /// <summary>79 /// Writes to PowerShell WDAC Audit mode ETW log.80 /// </summary>81 /// <param name="context">Current execution context.</param>82 /// <param name="title">Audit message title.</param>83 /// <param name="message">Audit message message.</param>84 /// <param name="fqid">Fully Qualified ID.</param>85 /// <param name="dropIntoDebugger">Stops code execution and goes into debugger mode.</param>86 internal static void LogWDACAuditMessage(87 ExecutionContext context,88 string title,89 string message,90 string fqid,91 bool dropIntoDebugger = false)92 {93 string messageToWrite = message;94 95 // Augment the log message with current script information from the script debugger, if available.96 context ??= LocalPipeline.GetExecutionContextFromTLS();97 bool debuggerAvailable = context is not null &&98 context._debugger is ScriptDebugger;99 100 if (debuggerAvailable)101 {102 var scriptPosMessage = context._debugger.GetCurrentScriptPosition();103 if (!string.IsNullOrEmpty(scriptPosMessage))104 {105 messageToWrite = message + scriptPosMessage;106 }107 }108 109 PSEtwLog.LogWDACAuditEvent(title, messageToWrite, fqid);110 111 // We drop into the debugger only if requested and we are running in the interactive host session runspace (Id == 1).112 if (debuggerAvailable && dropIntoDebugger &&113 context._debugger.DebugMode.HasFlag(DebugModes.LocalScript) &&114 Runspace.DefaultRunspace?.Id == 1 &&115 context.DebugPreferenceVariable.HasFlag(ActionPreference.Break) &&116 context.InternalHost?.UI is not null)117 {118 try119 {120 context.InternalHost.UI.WriteLine();121 context.InternalHost.UI.WriteLine("WDAC Audit Log:");122 context.InternalHost.UI.WriteLine($"Title: {title}");123 context.InternalHost.UI.WriteLine($"Message: {message}");124 context.InternalHost.UI.WriteLine($"FullyQualifedId: {fqid}");125 context.InternalHost.UI.WriteLine("Stopping script execution in debugger...");126 context.InternalHost.UI.WriteLine();127 128 context._debugger.Break();129 }130 catch131 { }132 }133 }134 135 /// <summary>136 /// Gets the system lockdown policy.137 /// </summary>138 /// <returns>An EnforcementMode that describes the system policy.</returns>139 public static SystemEnforcementMode GetSystemLockdownPolicy()140 {141 if (s_systemLockdownPolicy == null)142 {143 lock (s_systemLockdownPolicyLock)144 {145 s_systemLockdownPolicy ??= GetLockdownPolicy(path: null, handle: null);146 }147 }148 else if (s_allowDebugOverridePolicy)149 {150 lock (s_systemLockdownPolicyLock)151 {152 s_systemLockdownPolicy = GetDebugLockdownPolicy(path: null, out _);153 }154 }155 156 return s_systemLockdownPolicy.Value;157 }158 159 private static readonly object s_systemLockdownPolicyLock = new object();160 private static SystemEnforcementMode? s_systemLockdownPolicy = null;161 private static bool s_allowDebugOverridePolicy = false;162 private static bool s_wldpCanExecuteAvailable = true;163 164 /// <summary>165 /// Gets the system wide script file policy enforcement for an open file.166 /// Based on system WDAC (Windows Defender Application Control) or AppLocker policies.167 /// </summary>168 /// <param name="filePath">Script file path for policy check.</param>169 /// <param name="fileStream">FileStream object to script file path.</param>170 /// <returns>Policy check result for script file.</returns>171 public static SystemScriptFileEnforcement GetFilePolicyEnforcement(172 string filePath,173 System.IO.FileStream fileStream)174 {175 SafeHandle fileHandle = fileStream.SafeFileHandle;176 SystemEnforcementMode systemLockdownPolicy = GetSystemLockdownPolicy();177 178 // First check latest WDAC APIs if available.179 if (systemLockdownPolicy is SystemEnforcementMode.Enforce180 && s_wldpCanExecuteAvailable181 && TryGetWldpCanExecuteFileResult(filePath, fileHandle, out SystemScriptFileEnforcement wldpFilePolicy))182 {183 return GetLockdownPolicy(filePath, fileHandle, wldpFilePolicy);184 }185 186 // Failed to invoke WldpCanExecuteFile, revert to legacy APIs.187 if (systemLockdownPolicy is SystemEnforcementMode.None)188 {189 return SystemScriptFileEnforcement.None;190 }191 192 // WldpCanExecuteFile was invoked successfully so we can skip running193 // legacy WDAC APIs. AppLocker must still be checked in case it is more194 // strict than the current WDAC policy.195 return GetLockdownPolicy(filePath, fileHandle, canExecuteResult: null);196 }197 198 private static SystemScriptFileEnforcement ConvertToModernFileEnforcement(SystemEnforcementMode legacyMode)199 {200 return legacyMode switch201 {202 SystemEnforcementMode.None => SystemScriptFileEnforcement.Allow,203 SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit,204 SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained,205 _ => SystemScriptFileEnforcement.Block,206 };207 }208 209 private static bool TryGetWldpCanExecuteFileResult(string filePath, SafeHandle fileHandle, out SystemScriptFileEnforcement result)210 {211 try212 {213 string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);214 string auditMsg = $"PowerShell ExternalScriptInfo reading file: {fileName}";215 216 int hr = WldpNativeMethods.WldpCanExecuteFile(217 host: PowerShellHost,218 options: WLDP_EXECUTION_EVALUATION_OPTIONS.WLDP_EXECUTION_EVALUATION_OPTION_NONE,219 fileHandle: fileHandle.DangerousGetHandle(),220 auditInfo: auditMsg,221 result: out WLDP_EXECUTION_POLICY canExecuteResult);222 223 PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult);224 225 if (hr >= 0)226 {227 switch (canExecuteResult)228 {229 case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_ALLOWED:230 result = SystemScriptFileEnforcement.Allow;231 return true;232 233 case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_BLOCKED:234 result = SystemScriptFileEnforcement.Block;235 return true;236 237 case WLDP_EXECUTION_POLICY.WLDP_CAN_EXECUTE_REQUIRE_SANDBOX:238 result = SystemScriptFileEnforcement.AllowConstrained;239 return true;240 241 default:242 // Fall through to legacy system policy checks.243 Debug.Assert(false, $"Unknown policy result returned from WldCanExecute: {canExecuteResult}");244 break;245 }246 }247 248 // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks.249 }250 catch (Exception ex) when (ex is DllNotFoundException or EntryPointNotFoundException)251 {252 // Fall back to legacy system policy checks.253 s_wldpCanExecuteAvailable = false;254 PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, ex.HResult, 0);255 }256 257 result = default;258 return false;259 }260 261 /// <summary>262 /// Gets lockdown policy as applied to a file.263 /// </summary>264 /// <returns>An EnforcementMode that describes policy.</returns>265 public static SystemEnforcementMode GetLockdownPolicy(string path, SafeHandle handle)266 {267 SystemScriptFileEnforcement modernMode = GetLockdownPolicy(path, handle, canExecuteResult: null);268 Debug.Assert(269 modernMode is not SystemScriptFileEnforcement.Block,270 "Block should never be converted to legacy file enforcement.");271 272 return modernMode switch273 {274 SystemScriptFileEnforcement.Block => SystemEnforcementMode.Enforce,275 SystemScriptFileEnforcement.AllowConstrained => SystemEnforcementMode.Enforce,276 SystemScriptFileEnforcement.AllowConstrainedAudit => SystemEnforcementMode.Audit,277 SystemScriptFileEnforcement.Allow => SystemEnforcementMode.None,278 SystemScriptFileEnforcement.None => SystemEnforcementMode.None,279 _ => throw new ArgumentOutOfRangeException(nameof(modernMode)),280 };281 }282 283 private static SystemScriptFileEnforcement GetLockdownPolicy(284 string path,285 SafeHandle handle,286 SystemScriptFileEnforcement? canExecuteResult)287 {288 SystemScriptFileEnforcement wldpFilePolicy = canExecuteResult289 ?? ConvertToModernFileEnforcement(GetWldpPolicy(path, handle));290 291 // Check the WLDP File policy via API292 if (wldpFilePolicy is SystemScriptFileEnforcement.Block or SystemScriptFileEnforcement.AllowConstrained)293 {294 return wldpFilePolicy;295 }296 297 // Check the AppLocker File policy via API298 // This needs to be checked before WLDP audit policy299 // So, that we don't end up in Audit mode,300 // when we should be enforce mode.301 var appLockerFilePolicy = GetAppLockerPolicy(path, handle);302 if (appLockerFilePolicy == SystemEnforcementMode.Enforce)303 {304 return ConvertToModernFileEnforcement(appLockerFilePolicy);305 }306 307 // At this point, LockdownPolicy = Audit or Allowed.308 // If there was a WLDP policy, but WLDP didn't block it,309 // then it was explicitly allowed. Therefore, return the result for the file.310 if (s_cachedWldpSystemPolicy is SystemEnforcementMode.Audit or SystemEnforcementMode.Enforce311 || wldpFilePolicy is SystemScriptFileEnforcement.AllowConstrainedAudit)312 {313 return wldpFilePolicy;314 }315 316 // If there was a system-wide AppLocker policy, but AppLocker didn't block it,317 // then return AppLocker's status.318 if (s_cachedSaferSystemPolicy is SaferPolicy.Disallowed)319 {320 return ConvertToModernFileEnforcement(appLockerFilePolicy);321 }322 323 // If it's not set to 'Enforce' by the platform, allow debug overrides324 GetDebugLockdownPolicy(path, out SystemScriptFileEnforcement debugPolicy);325 return debugPolicy;326 }327 328 [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods",329 MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle")]330 private static SystemEnforcementMode GetWldpPolicy(string path, SafeHandle handle)331 {332 // If the WLDP assembly is missing (such as windows 7 or down OS), return default/None to skip WLDP validation333 if (s_hadMissingWldpAssembly)334 {335 return s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None);336 }337 338 // If path is NULL, see if we have the cached system-wide lockdown policy.339 if (string.IsNullOrEmpty(path))340 {341 if ((s_cachedWldpSystemPolicy != null) && (!InternalTestHooks.BypassAppLockerPolicyCaching))342 {343 return s_cachedWldpSystemPolicy.Value;344 }345 }346 347 try348 {349 WLDP_HOST_INFORMATION hostInformation = new WLDP_HOST_INFORMATION();350 hostInformation.dwRevision = WldpNativeConstants.WLDP_HOST_INFORMATION_REVISION;351 hostInformation.dwHostId = WLDP_HOST_ID.WLDP_HOST_ID_POWERSHELL;352 353 if (!string.IsNullOrEmpty(path))354 {355 hostInformation.szSource = path;356 357 if (handle != null)358 {359 IntPtr fileHandle = IntPtr.Zero;360 fileHandle = handle.DangerousGetHandle();361 hostInformation.hSource = fileHandle;362 }363 }364 365 uint pdwLockdownState = 0;366 int result = WldpNativeMethods.WldpGetLockdownPolicy(ref hostInformation, ref pdwLockdownState, 0);367 PSEtwLog.LogWDACQueryEvent("WldpGetLockdownPolicy", path, result, (int)pdwLockdownState);368 if (result >= 0)369 {370 SystemEnforcementMode resultingLockdownPolicy = GetLockdownPolicyForResult(pdwLockdownState);371 372 // If this is a query for the system-wide lockdown policy, cache it.373 if (string.IsNullOrEmpty(path))374 {375 s_cachedWldpSystemPolicy = resultingLockdownPolicy;376 }377 378 return resultingLockdownPolicy;379 }380 else381 {382 // API failure?383 return SystemEnforcementMode.Enforce;384 }385 }386 catch (DllNotFoundException ex)387 {388 s_hadMissingWldpAssembly = true;389 PSEtwLog.LogWDACQueryEvent("WldpGetLockdownPolicy_Failed", path, ex.HResult, 0);390 return s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None);391 }392 }393 394 private static SystemEnforcementMode? s_cachedWldpSystemPolicy = null;395 396 private const string AppLockerTestFileName = "__PSScriptPolicyTest_";397 private const string AppLockerTestFileContents = "# PowerShell test file to determine AppLocker lockdown mode ";398 399 private static SystemEnforcementMode GetAppLockerPolicy(string path, SafeHandle handle)400 {401 SaferPolicy result = SaferPolicy.Disallowed;402 403 // If path is NULL, we're looking for the system-wide lockdown policy.404 // Since there is no way to get that from AppLocker, we will test the policy405 // against a random non-existent script and module. If that is allowed, then there is406 // no AppLocker script policy.407 if (string.IsNullOrEmpty(path))408 {409 if ((s_cachedSaferSystemPolicy != null) && (!InternalTestHooks.BypassAppLockerPolicyCaching))410 {411 result = s_cachedSaferSystemPolicy.Value;412 }413 else414 {415 //416 // Temp path can sometimes be deleted. While many places in PowerShell depend on its existence,417 // this one can crash PowerShell.418 // A less sensitive implementation will be possible once AppLocker allows validation of files that419 // don't exist.420 //421 422 string testPathScript = null;423 string testPathModule = null;424 try425 {426 // Start with the current profile temp path.427 string tempPath = IO.Path.GetTempPath();428 429 int iteration = 0;430 while (iteration++ < 2)431 {432 bool error = false;433 434 try435 {436 if (!IO.Directory.Exists(tempPath))437 {438 IO.Directory.CreateDirectory(tempPath);439 }440 441 testPathScript = IO.Path.Combine(tempPath, AppLockerTestFileName + IO.Path.GetRandomFileName() + ".ps1");442 testPathModule = IO.Path.Combine(tempPath, AppLockerTestFileName + IO.Path.GetRandomFileName() + ".psm1");443 444 // AppLocker fails when you try to check a policy on a file445 // with no content. So create a scratch file and test on that.446 string dtAppLockerTestFileContents = AppLockerTestFileContents + Environment.TickCount64;447 IO.File.WriteAllText(testPathScript, dtAppLockerTestFileContents);448 IO.File.WriteAllText(testPathModule, dtAppLockerTestFileContents);449 }450 catch (IO.IOException)451 {452 if (iteration == 2)453 {454 throw;455 }456 457 error = true;458 }459 catch (UnauthorizedAccessException)460 {461 if (iteration == 2)462 {463 throw;464 }465 466 error = true;467 }468 catch (System.Security.SecurityException)469 {470 if (iteration == 2)471 {472 throw;473 }474 475 error = true;476 }477 478 if (!error)479 {480 break;481 }482 483 // Try again with the AppData\LocalLow\Temp path using known folder id:484 // https://msdn.microsoft.com/library/dd378457.aspx485 Guid AppDatalocalLowFolderId = new Guid("A520A1A4-1780-4FF6-BD18-167343C5AF16");486 tempPath = GetKnownFolderPath(AppDatalocalLowFolderId) + @"\Temp";487 }488 489 // Test policy.490 result = TestSaferPolicy(testPathScript, testPathModule);491 }492 catch (System.IO.IOException)493 {494 // If we fail to test the policy, assume the default.495 result = SaferPolicy.Disallowed;496 }497 catch (System.UnauthorizedAccessException)498 {499 // This can happen during thread impersonation if the profile temp paths are not accessible.500 // Allow policy if impersonated, otherwise disallow.501 result =502 (System.Security.Principal.WindowsIdentity.GetCurrent().ImpersonationLevel == System.Security.Principal.TokenImpersonationLevel.Impersonation) ?503 SaferPolicy.Allowed : SaferPolicy.Disallowed;504 }505 catch (ArgumentException)506 {507 // This is for IO.Path.GetTempPath() call when temp paths are not accessible.508 result =509 (System.Security.Principal.WindowsIdentity.GetCurrent().ImpersonationLevel == System.Security.Principal.TokenImpersonationLevel.Impersonation) ?510 SaferPolicy.Allowed : SaferPolicy.Disallowed;511 }512 finally513 {514 // Ok to leave the test scripts in the temp folder if they happen to be in use515 // so that PowerShell will still startup.516 PathUtils.TryDeleteFile(testPathScript);517 PathUtils.TryDeleteFile(testPathModule);518 }519 520 s_cachedSaferSystemPolicy = result;521 }522 523 if (result == SaferPolicy.Disallowed)524 {525 return SystemEnforcementMode.Enforce;526 }527 else528 {529 return SystemEnforcementMode.None;530 }531 }532 else533 {534 // We got a path. Return the result for that path.535 result = SecuritySupport.GetSaferPolicy(path, handle);536 if (result == SaferPolicy.Disallowed)537 {538 return SystemEnforcementMode.Enforce;539 }540 541 return SystemEnforcementMode.None;542 }543 }544 545 private static SaferPolicy? s_cachedSaferSystemPolicy = null;546 547 private static string GetKnownFolderPath(Guid knownFolderId)548 {549 IntPtr pszPath = IntPtr.Zero;550 try551 {552 int hr = WldpNativeMethods.SHGetKnownFolderPath(knownFolderId, 0, IntPtr.Zero, out pszPath);553 if (hr >= 0)554 {555 return Marshal.PtrToStringAuto(pszPath);556 }557 558 throw new System.IO.IOException();559 }560 finally561 {562 if (pszPath != IntPtr.Zero)563 {564 Marshal.FreeCoTaskMem(pszPath);565 }566 }567 }568 569 private static SaferPolicy TestSaferPolicy(string testPathScript, string testPathModule)570 {571 SaferPolicy result = SecuritySupport.GetSaferPolicy(testPathScript, null);572 if (result == SaferPolicy.Disallowed)573 {574 result = SecuritySupport.GetSaferPolicy(testPathModule, null);575 }576 577 return result;578 }579 580 private static SystemEnforcementMode GetDebugLockdownPolicy(string path, out SystemScriptFileEnforcement modernEnforcement)581 {582 s_allowDebugOverridePolicy = true;583 584 // Support fall-back debug hook for path exclusions on non-WOA platforms585 if (path != null)586 {587 // Assume everything under SYSTEM32 is trusted, with a purposefully sloppy588 // check so that we can actually put it in the filename during testing.589 if (path.Contains("System32", StringComparison.OrdinalIgnoreCase))590 {591 modernEnforcement = SystemScriptFileEnforcement.Allow;592 return SystemEnforcementMode.None;593 }594 595 // No explicit debug allowance for the file, so return the system policy if there is one.596 modernEnforcement = s_systemLockdownPolicy switch597 {598 SystemEnforcementMode.Enforce => SystemScriptFileEnforcement.AllowConstrained,599 SystemEnforcementMode.Audit => SystemScriptFileEnforcement.AllowConstrainedAudit,600 SystemEnforcementMode.None => SystemScriptFileEnforcement.None,601 _ => SystemScriptFileEnforcement.None,602 };603 604 return s_systemLockdownPolicy.GetValueOrDefault(SystemEnforcementMode.None);605 }606 607 // Support fall-back debug hook for system-wide policy on non-WOA platforms608 uint pdwLockdownState = 0;609 object result = Environment.GetEnvironmentVariable("__PSLockdownPolicy", EnvironmentVariableTarget.Machine);610 if (result != null)611 {612 pdwLockdownState = LanguagePrimitives.ConvertTo<uint>(result);613 SystemEnforcementMode policy = GetLockdownPolicyForResult(pdwLockdownState);614 modernEnforcement = ConvertToModernFileEnforcement(policy);615 return policy;616 }617 618 // If the system-wide debug policy had no preference, then there is no enforcement.619 modernEnforcement = SystemScriptFileEnforcement.None;620 return SystemEnforcementMode.None;621 }622 623 private static bool s_hadMissingWldpAssembly = false;624 625 /// <summary>626 /// Gets lockdown policy as applied to a COM object.627 /// </summary>628 /// <returns>True if the COM object is allowed, False otherwise.</returns>629 internal static bool IsClassInApprovedList(Guid clsid)630 {631 // This method is called only if there is an AppLocker and/or WLDP system wide lock down enforcement policy.632 if (s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None) != SystemEnforcementMode.Enforce)633 {634 // No WLDP policy implies only AppLocker policy enforcement. Disallow all COM object instantiation.635 return false;636 }637 638 // WLDP policy must be in system wide enforcement, look up COM Id in WLDP approval list.639 try640 {641 WLDP_HOST_INFORMATION hostInformation = new WLDP_HOST_INFORMATION();642 hostInformation.dwRevision = WldpNativeConstants.WLDP_HOST_INFORMATION_REVISION;643 hostInformation.dwHostId = WLDP_HOST_ID.WLDP_HOST_ID_POWERSHELL;644 645 int pIsApproved = 0;646 int result = WldpNativeMethods.WldpIsClassInApprovedList(ref clsid, ref hostInformation, ref pIsApproved, 0);647 648 if (result >= 0)649 {650 if (pIsApproved == 1)651 {652 // Hook for testability. If we've got an environmental override, say that ADODB.Parameter653 // is not allowed.654 // 0000050b-0000-0010-8000-00aa006d2ea4 = ADODB.Parameter655 if (s_allowDebugOverridePolicy)656 {657 if (string.Equals(clsid.ToString(), "0000050b-0000-0010-8000-00aa006d2ea4", StringComparison.OrdinalIgnoreCase))658 {659 return false;660 }661 }662 663 return true;664 }665 }666 667 return false;668 }669 catch (DllNotFoundException)670 {671 // Hook for testability. IsClassInApprovedList is only called when the system is in global lockdown mode,672 // so this wouldn't be allowed in regular ConstrainedLanguage mode.673 // f6d90f11-9c73-11d3-b32e-00c04f990bb4 = MSXML2.DOMDocument674 if (string.Equals(clsid.ToString(), "f6d90f11-9c73-11d3-b32e-00c04f990bb4", StringComparison.OrdinalIgnoreCase))675 {676 return true;677 }678 679 return false;680 }681 }682 683 private static SystemEnforcementMode GetLockdownPolicyForResult(uint pdwLockdownState)684 {685 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_UMCIAUDIT_FLAG) ==686 SystemPolicy.WldpNativeConstants.WLDP_LOCKDOWN_UMCIAUDIT_FLAG)687 {688 return SystemEnforcementMode.Audit;689 }690 else if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_UMCIENFORCE_FLAG) ==691 WldpNativeConstants.WLDP_LOCKDOWN_UMCIENFORCE_FLAG)692 {693 return SystemEnforcementMode.Enforce;694 }695 else696 {697 return SystemEnforcementMode.None;698 }699 }700 701 internal static string DumpLockdownState(uint pdwLockdownState)702 {703 string returnValue = string.Empty;704 705 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_DEFINED_FLAG) == WldpNativeConstants.WLDP_LOCKDOWN_DEFINED_FLAG)706 {707 returnValue += "WLDP_LOCKDOWN_DEFINED_FLAG\r\n";708 }709 710 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_SECUREBOOT_FLAG) == WldpNativeConstants.WLDP_LOCKDOWN_SECUREBOOT_FLAG)711 {712 returnValue += "WLDP_LOCKDOWN_SECUREBOOT_FLAG\r\n";713 }714 715 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_DEBUGPOLICY_FLAG) == WldpNativeConstants.WLDP_LOCKDOWN_DEBUGPOLICY_FLAG)716 {717 returnValue += "WLDP_LOCKDOWN_DEBUGPOLICY_FLAG\r\n";718 }719 720 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_UMCIENFORCE_FLAG) == WldpNativeConstants.WLDP_LOCKDOWN_UMCIENFORCE_FLAG)721 {722 returnValue += "WLDP_LOCKDOWN_UMCIENFORCE_FLAG\r\n";723 }724 725 if ((pdwLockdownState & WldpNativeConstants.WLDP_LOCKDOWN_UMCIAUDIT_FLAG) == WldpNativeConstants.WLDP_LOCKDOWN_UMCIAUDIT_FLAG)726 {727 returnValue += "WLDP_LOCKDOWN_UMCIAUDIT_FLAG\r\n";728 }729 730 return returnValue;731 }732 733 // Overrides for features that should only be enabled in debug mode734 internal static bool XamlWorkflowSupported { get; set; }735 736 /// <summary>737 /// Native constants for dealing with the lockdown policy.738 /// </summary>739 internal static class WldpNativeConstants740 {741 internal const uint WLDP_HOST_INFORMATION_REVISION = 0x00000001;742 743 internal const uint WLDP_LOCKDOWN_UNDEFINED = 0;744 internal const uint WLDP_LOCKDOWN_DEFINED_FLAG = 0x80000000;745 internal const uint WLDP_LOCKDOWN_SECUREBOOT_FLAG = 1;746 internal const uint WLDP_LOCKDOWN_DEBUGPOLICY_FLAG = 2;747 internal const uint WLDP_LOCKDOWN_UMCIENFORCE_FLAG = 4;748 internal const uint WLDP_LOCKDOWN_UMCIAUDIT_FLAG = 8;749 }750 751 /// <summary>752 /// The different host IDs understood by the lockdown policy.753 /// </summary>754 internal enum WLDP_HOST_ID755 {756 WLDP_HOST_ID_UNKNOWN = 0,757 WLDP_HOST_ID_GLOBAL = 1,758 WLDP_HOST_ID_VBA = 2,759 WLDP_HOST_ID_WSH = 3,760 WLDP_HOST_ID_POWERSHELL = 4,761 WLDP_HOST_ID_IE = 5,762 WLDP_HOST_ID_MSI = 6,763 WLDP_HOST_ID_MAX = 7,764 }765 766 /// <summary>767 /// Host information structure to contain the lockdown policy request.768 /// </summary>769 [StructLayoutAttribute(LayoutKind.Sequential)]770 internal struct WLDP_HOST_INFORMATION771 {772 /// DWORD->unsigned int773 internal uint dwRevision;774 775 /// WLDP_HOST_ID->_WLDP_HOST_ID776 internal WLDP_HOST_ID dwHostId;777 778 /// PCWSTR->WCHAR*779 [MarshalAsAttribute(UnmanagedType.LPWStr)]780 internal string szSource;781 782 // HANDLE->IntPtr783 internal IntPtr hSource;784 }785 786 /// <summary>787 /// Options for WldpCanExecuteFile method.788 /// </summary>789 [Flags]790 internal enum WLDP_EXECUTION_EVALUATION_OPTIONS791 {792 WLDP_EXECUTION_EVALUATION_OPTION_NONE = 0x0,793 WLDP_EXECUTION_EVALUATION_OPTION_EXECUTE_IN_INTERACTIVE_SESSION = 0x1794 }795 796 /// <summary>797 /// Results from WldpCanExecuteFile method.798 /// </summary>799 internal enum WLDP_EXECUTION_POLICY800 {801 WLDP_CAN_EXECUTE_BLOCKED = 0,802 WLDP_CAN_EXECUTE_ALLOWED = 1,803 WLDP_CAN_EXECUTE_REQUIRE_SANDBOX = 2804 }805 806 /// <summary>807 /// Powershell Script Host.808 /// </summary>809 internal static readonly Guid PowerShellHost = new Guid("8E9AAA7C-198B-4879-AE41-A50D47AD6458");810 811 /// <summary>812 /// Native methods for dealing with the lockdown policy.813 /// </summary>814 internal static class WldpNativeMethods815 {816 /// <summary>817 /// Returns a WLDP_EXECUTION_POLICY enum value indicating if and how a script file818 /// should be executed.819 /// </summary>820 /// <param name="host">Host guid.</param>821 /// <param name="options">Evaluation options.</param>822 /// <param name="fileHandle">Evaluated file handle.</param>823 /// <param name="auditInfo">Auditing information string.</param>824 /// <param name="result">Evaluation result.</param>825 /// <returns>HResult value.</returns>826 [DefaultDllImportSearchPathsAttribute(DllImportSearchPath.System32)]827 [DllImportAttribute("wldp.dll", EntryPoint = "WldpCanExecuteFile")]828 internal static extern int WldpCanExecuteFile(829 [MarshalAs(UnmanagedType.LPStruct)]830 Guid host,831 WLDP_EXECUTION_EVALUATION_OPTIONS options,832 IntPtr fileHandle,833 [MarshalAs(UnmanagedType.LPWStr)]834 string auditInfo,835 out WLDP_EXECUTION_POLICY result);836 837 /// Return Type: HRESULT->LONG->int838 /// pHostInformation: PWLDP_HOST_INFORMATION->_WLDP_HOST_INFORMATION*839 /// pdwLockdownState: PDWORD->DWORD*840 /// dwFlags: DWORD->unsigned int841 [DefaultDllImportSearchPathsAttribute(DllImportSearchPath.System32)]842 [DllImportAttribute("wldp.dll", EntryPoint = "WldpGetLockdownPolicy")]843 internal static extern int WldpGetLockdownPolicy(844 ref WLDP_HOST_INFORMATION pHostInformation,845 ref uint pdwLockdownState,846 uint dwFlags);847 848 /// Return Type: HRESULT->LONG->int849 /// rclsid: IID*850 /// pHostInformation: PWLDP_HOST_INFORMATION->_WLDP_HOST_INFORMATION*851 /// ptIsApproved: PBOOL->BOOL*852 /// dwFlags: DWORD->unsigned int853 [DefaultDllImportSearchPathsAttribute(DllImportSearchPath.System32)]854 [DllImportAttribute("wldp.dll", EntryPoint = "WldpIsClassInApprovedList")]855 internal static extern int WldpIsClassInApprovedList(856 ref Guid rclsid,857 ref WLDP_HOST_INFORMATION pHostInformation,858 ref int ptIsApproved,859 uint dwFlags);860 861 [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]862 internal static extern int SHGetKnownFolderPath(863 [MarshalAs(UnmanagedType.LPStruct)]864 Guid rfid,865 int dwFlags,866 IntPtr hToken,867 out IntPtr pszPath);868 }869 }870}871 872#endif873 