MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#pragma warning disable 1634, 16915#pragma warning disable 565066 7using System;8using System.Collections.Generic;9using System.Collections.ObjectModel;10using System.ComponentModel;11using System.Diagnostics.CodeAnalysis;12using System.Globalization;13using System.Management.Automation;14using System.Management.Automation.Security;15using System.Runtime.InteropServices;16using System.Security.AccessControl;17using System.Security.Principal;18 19using Dbg = System.Management.Automation;20 21namespace Microsoft.PowerShell.Commands22{23 /// <summary>24 /// Defines the base class from which all Security Descriptor commands25 /// are derived.26 /// </summary>27 public abstract class SecurityDescriptorCommandsBase : PSCmdlet28 {29 /// <summary>30 /// Gets or sets the filter property. The filter31 /// property allows for provider-specific filtering of results.32 /// </summary>33 [Parameter]34 public string Filter35 {36 get37 {38 return _filter;39 }40 41 set42 {43 _filter = value;44 }45 }46 47 /// <summary>48 /// Gets or sets the include property. The include property49 /// specifies the items on which the command will act.50 /// </summary>51 [Parameter]52 public string[] Include53 {54 get55 {56 return _include;57 }58 59 set60 {61 _include = value;62 }63 }64 65 /// <summary>66 /// Gets or sets the exclude property. The exclude property67 /// specifies the items on which the command will not act.68 /// </summary>69 [Parameter]70 public string[] Exclude71 {72 get73 {74 return _exclude;75 }76 77 set78 {79 _exclude = value;80 }81 }82 83 /// <summary>84 /// The context for the command that is passed to the core command providers.85 /// </summary>86 internal CmdletProviderContext CmdletProviderContext87 {88 get89 {90 CmdletProviderContext coreCommandContext = new(this);91 92 Collection<string> includeFilter =93 SessionStateUtilities.ConvertArrayToCollection<string>(Include);94 95 Collection<string> excludeFilter =96 SessionStateUtilities.ConvertArrayToCollection<string>(Exclude);97 98 coreCommandContext.SetFilters(includeFilter,99 excludeFilter,100 Filter);101 102 return coreCommandContext;103 }104 }105 106 #region brokered properties107 108 /// <summary>109 /// Add brokered properties for easy access to important properties110 /// of security descriptor.111 /// </summary>112 internal static void AddBrokeredProperties(113 Collection<PSObject> results,114 bool audit,115 bool allCentralAccessPolicies)116 {117 foreach (PSObject result in results)118 {119 if (audit)120 {121 // Audit122 result.Properties.Add123 (124 new PSCodeProperty125 (126 "Audit",127 typeof(SecurityDescriptorCommandsBase).GetMethod("GetAudit")128 )129 );130 }131 // CentralAccessPolicyId retrieval does not require elevation, so we always add this property.132 result.Properties.Add133 (134 new PSCodeProperty135 (136 "CentralAccessPolicyId",137 typeof(SecurityDescriptorCommandsBase).GetMethod("GetCentralAccessPolicyId")138 )139 );140#if !CORECLR // GetAllCentralAccessPolicies and GetCentralAccessPolicyName are not supported in OneCore powershell141 // because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.142 if (allCentralAccessPolicies)143 {144 // AllCentralAccessPolicies145 result.Properties.Add146 (147 new PSCodeProperty148 (149 "AllCentralAccessPolicies",150 typeof(SecurityDescriptorCommandsBase).GetMethod("GetAllCentralAccessPolicies")151 )152 );153 }154 // CentralAccessPolicyName retrieval does not require elevation, so we always add this property.155 result.Properties.Add156 (157 new PSCodeProperty158 (159 "CentralAccessPolicyName",160 typeof(SecurityDescriptorCommandsBase).GetMethod("GetCentralAccessPolicyName")161 )162 );163#endif164 }165 }166 167 /// <summary>168 /// Gets the Path of the provided PSObject.169 /// </summary>170 /// <param name="instance">171 /// The PSObject for which to obtain the path.172 /// </param>173 /// <returns>174 /// The path of the provided PSObject.175 /// </returns>176 public static string GetPath(PSObject instance)177 {178 if (instance == null)179 {180 throw PSTraceSource.NewArgumentNullException(nameof(instance));181 }182 else183 {184 // These are guaranteed to not be null, but even checking185 // them for null causes a presharp warning186#pragma warning disable 56506187 188 // Get path189 return instance.Properties["PSPath"].Value.ToString();190#pragma warning restore 56506191 }192 }193 194 /// <summary>195 /// Gets the Owner of the provided PSObject.196 /// </summary>197 /// <param name="instance">198 /// The PSObject for which to obtain the Owner.199 /// </param>200 /// <returns>201 /// The Owner of the provided PSObject.202 /// </returns>203 public static string GetOwner(PSObject instance)204 {205 if (instance == null)206 {207 throw PSTraceSource.NewArgumentNullException(nameof(instance));208 }209 210 if (instance.BaseObject is not ObjectSecurity sd)211 {212 throw PSTraceSource.NewArgumentNullException(nameof(instance));213 }214 215 // Get owner216 try217 {218 IdentityReference ir = sd.GetOwner(typeof(NTAccount));219 return ir.ToString();220 }221 catch (IdentityNotMappedException)222 {223 // All Acl cmdlets returning SIDs will return a string224 // representation of the SID in all cases where the SID225 // cannot be mapped to a proper user or group name.226 }227 228 // We are here since we cannot get IdentityReference from sd..229 // So return sddl..230 return sd.GetSecurityDescriptorSddlForm(AccessControlSections.Owner);231 }232 233 /// <summary>234 /// Gets the Group of the provided PSObject.235 /// </summary>236 /// <param name="instance">237 /// The PSObject for which to obtain the Group.238 /// </param>239 /// <returns>240 /// The Group of the provided PSObject.241 /// </returns>242 public static string GetGroup(PSObject instance)243 {244 if (instance == null)245 {246 throw PSTraceSource.NewArgumentNullException(nameof(instance));247 }248 249 if (instance.BaseObject is not ObjectSecurity sd)250 {251 throw PSTraceSource.NewArgumentNullException(nameof(instance));252 }253 254 // Get Group255 try256 {257 IdentityReference ir = sd.GetGroup(typeof(NTAccount));258 return ir.ToString();259 }260 catch (IdentityNotMappedException)261 {262 // All Acl cmdlets returning SIDs will return a string263 // representation of the SID in all cases where the SID264 // cannot be mapped to a proper user or group name.265 }266 267 // We are here since we cannot get IdentityReference from sd..268 // So return sddl..269 return sd.GetSecurityDescriptorSddlForm(AccessControlSections.Group);270 }271 /// <summary>272 /// Gets the access rules of the provided PSObject.273 /// </summary>274 /// <param name="instance">275 /// The PSObject for which to obtain the access rules.276 /// </param>277 /// <returns>278 /// The access rules of the provided PSObject.279 /// </returns>280 public static AuthorizationRuleCollection GetAccess(PSObject instance)281 {282 if (instance == null)283 {284 throw PSTraceSource.NewArgumentNullException(nameof(instance));285 }286 287 ObjectSecurity sd = instance.BaseObject as ObjectSecurity;288 if (sd == null)289 {290 PSTraceSource.NewArgumentException(nameof(instance));291 }292 293 // Get DACL294 if (sd is CommonObjectSecurity cos)295 {296 return cos.GetAccessRules(true, true, typeof(NTAccount));297 }298 else299 {300 DirectoryObjectSecurity dos = sd as DirectoryObjectSecurity;301 Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity");302 return dos.GetAccessRules(true, true, typeof(NTAccount));303 }304 }305 306 /// <summary>307 /// Gets the audit rules of the provided PSObject.308 /// </summary>309 /// <param name="instance">310 /// The PSObject for which to obtain the audit rules.311 /// </param>312 /// <returns>313 /// The audit rules of the provided PSObject.314 /// </returns>315 public static AuthorizationRuleCollection GetAudit(PSObject instance)316 {317 if (instance == null)318 {319 throw PSTraceSource.NewArgumentNullException(nameof(instance));320 }321 322 ObjectSecurity sd = instance.BaseObject as ObjectSecurity;323 if (sd == null)324 {325 PSTraceSource.NewArgumentException(nameof(instance));326 }327 328 if (sd is CommonObjectSecurity cos)329 {330 return cos.GetAuditRules(true, true, typeof(NTAccount));331 }332 else333 {334 DirectoryObjectSecurity dos = sd as DirectoryObjectSecurity;335 Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity");336 return dos.GetAuditRules(true, true, typeof(NTAccount));337 }338 }339 340 /// <summary>341 /// Gets the central access policy ID of the provided PSObject.342 /// </summary>343 /// <param name="instance">344 /// The PSObject for which to obtain the central access policy ID.345 /// </param>346 /// <returns>347 /// The central access policy ID of the provided PSObject.348 /// </returns>349 public static SecurityIdentifier GetCentralAccessPolicyId(PSObject instance)350 {351 SessionState sessionState = new();352 string path = sessionState.Path.GetUnresolvedProviderPathFromPSPath(353 GetPath(instance));354 IntPtr pSd = IntPtr.Zero;355 356 try357 {358 // Get the file's SACL containing the CAPID ACE.359 uint rs = NativeMethods.GetNamedSecurityInfo(360 path,361 NativeMethods.SeObjectType.SE_FILE_OBJECT,362 NativeMethods.SecurityInformation.SCOPE_SECURITY_INFORMATION,363 out IntPtr pOwner,364 out IntPtr pGroup,365 out IntPtr pDacl,366 out IntPtr pSacl,367 out pSd);368 if (rs != NativeMethods.ERROR_SUCCESS)369 {370 throw new Win32Exception((int)rs);371 }372 373 if (pSacl == IntPtr.Zero)374 {375 return null;376 }377 378 NativeMethods.ACL sacl = Marshal.PtrToStructure<NativeMethods.ACL>(pSacl);379 if (sacl.AceCount == 0)380 {381 return null;382 }383 384 // Extract the first CAPID from the SACL that does not have INHERIT_ONLY_ACE flag set.385 IntPtr pAce = pSacl + Marshal.SizeOf(new NativeMethods.ACL());386 for (ushort aceIdx = 0; aceIdx < sacl.AceCount; aceIdx++)387 {388 NativeMethods.ACE_HEADER ace = Marshal.PtrToStructure<NativeMethods.ACE_HEADER>(pAce);389 Dbg.Diagnostics.Assert(ace.AceType ==390 NativeMethods.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE,391 "Unexpected ACE type: " + ace.AceType.ToString(CultureInfo.CurrentCulture));392 if ((ace.AceFlags & NativeMethods.INHERIT_ONLY_ACE) == 0)393 {394 break;395 }396 397 pAce += ace.AceSize;398 }399 400 IntPtr pSid = pAce + Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) -401 Marshal.SizeOf(new uint());402 bool ret = NativeMethods.IsValidSid(pSid);403 if (!ret)404 {405 throw new Win32Exception(Marshal.GetLastWin32Error());406 }407 408 return new SecurityIdentifier(pSid);409 }410 finally411 {412 NativeMethods.LocalFree(pSd);413 }414 }415 416#if !CORECLR417 /// <summary>418 /// Gets the central access policy name of the provided PSObject.419 /// </summary>420 /// <remarks>421 /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.422 /// </remarks>423 /// <param name="instance">424 /// The PSObject for which to obtain the central access policy name.425 /// </param>426 /// <returns>427 /// The central access policy name of the provided PSObject.428 /// </returns>429 public static string GetCentralAccessPolicyName(PSObject instance)430 {431 SecurityIdentifier capId = GetCentralAccessPolicyId(instance);432 if (capId == null)433 {434 return null; // file does not have the scope ace435 }436 437 int capIdSize = capId.BinaryLength;438 byte[] capIdArray = new byte[capIdSize];439 capId.GetBinaryForm(capIdArray, 0);440 IntPtr caps = IntPtr.Zero;441 IntPtr pCapId = Marshal.AllocHGlobal(capIdSize);442 443 try444 {445 // Retrieve the CAP by CAPID.446 Marshal.Copy(capIdArray, 0, pCapId, capIdSize);447 IntPtr[] ppCapId = new IntPtr[1];448 ppCapId[0] = pCapId;449 uint rs = NativeMethods.LsaQueryCAPs(450 ppCapId,451 1,452 out caps,453 out uint capCount);454 if (rs != NativeMethods.STATUS_SUCCESS)455 {456 throw new Win32Exception((int)rs);457 }458 459 if (capCount == 0 || caps == IntPtr.Zero)460 {461 return null;462 }463 464 // Get the CAP name.465 NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(caps);466 // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.467 return Marshal.PtrToStringUni(cap.Name.Buffer, cap.Name.Length / 2);468 }469 finally470 {471 Marshal.FreeHGlobal(pCapId);472 uint rs = NativeMethods.LsaFreeMemory(caps);473 Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS,474 "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture));475 }476 }477 478 /// <summary>479 /// Gets the names and IDs of all central access policies available on the machine.480 /// </summary>481 /// <remarks>482 /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.483 /// </remarks>484 /// <param name="instance">485 /// The PSObject argument is ignored.486 /// </param>487 /// <returns>488 /// The names and IDs of all central access policies available on the machine.489 /// </returns>490 public static string[] GetAllCentralAccessPolicies(PSObject instance)491 {492 IntPtr caps = IntPtr.Zero;493 494 try495 {496 // Retrieve all CAPs.497 uint rs = NativeMethods.LsaQueryCAPs(498 null,499 0,500 out caps,501 out uint capCount);502 if (rs != NativeMethods.STATUS_SUCCESS)503 {504 throw new Win32Exception((int)rs);505 }506 507 Dbg.Diagnostics.Assert(capCount < 0xFFFF,508 "Too many central access policies");509 if (capCount == 0 || caps == IntPtr.Zero)510 {511 return null;512 }513 514 // Add CAP names and IDs to a string array.515 string[] policies = new string[capCount];516 IntPtr capPtr = caps;517 for (uint capIdx = 0; capIdx < capCount; capIdx++)518 {519 // Retrieve CAP name.520 Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero,521 "Invalid central access policies array");522 NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr);523 // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.524 policies[capIdx] = "\"" + Marshal.PtrToStringUni(525 cap.Name.Buffer,526 cap.Name.Length / 2) + "\"";527 528 // Retrieve CAPID.529 IntPtr pCapId = cap.CAPID;530 Dbg.Diagnostics.Assert(pCapId != IntPtr.Zero,531 "Invalid central access policies array");532 bool ret = NativeMethods.IsValidSid(pCapId);533 if (!ret)534 {535 throw new Win32Exception(Marshal.GetLastWin32Error());536 }537 538 SecurityIdentifier sid = new SecurityIdentifier(pCapId);539 policies[capIdx] += " (" + sid.ToString() + ")";540 541 capPtr += Marshal.SizeOf(cap);542 }543 544 return policies;545 }546 finally547 {548 uint rs = NativeMethods.LsaFreeMemory(caps);549 Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS,550 "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture));551 }552 }553#endif554 555 /// <summary>556 /// Gets the security descriptor (in SDDL form) of the557 /// provided PSObject. SDDL form is the Security Descriptor558 /// Definition Language.559 /// </summary>560 /// <param name="instance">561 /// The PSObject for which to obtain the security descriptor.562 /// </param>563 /// <returns>564 /// The security descriptor of the provided PSObject, in SDDL form.565 /// </returns>566 public static string GetSddl(PSObject instance)567 {568 if (instance == null)569 {570 throw PSTraceSource.NewArgumentNullException(nameof(instance));571 }572 573 if (instance.BaseObject is not ObjectSecurity sd)574 {575 throw PSTraceSource.NewArgumentNullException(nameof(instance));576 }577 578 string sddl = sd.GetSecurityDescriptorSddlForm(AccessControlSections.All);579 return sddl;580 }581 582 #endregion brokered properties583 584 /// <summary>585 /// The filter to be used to when globbing to get the item.586 /// </summary>587 private string _filter;588 589 /// <summary>590 /// The glob string used to determine which items are included.591 /// </summary>592 private string[] _include = Array.Empty<string>();593 594 /// <summary>595 /// The glob string used to determine which items are excluded.596 /// </summary>597 private string[] _exclude = Array.Empty<string>();598 }599 600#if !UNIX601 /// <summary>602 /// Defines the implementation of the 'get-acl' cmdlet.603 /// This cmdlet gets the security descriptor of an item at the specified path.604 /// </summary>605 [Cmdlet(VerbsCommon.Get, "Acl", SupportsTransactions = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096593")]606 public sealed class GetAclCommand : SecurityDescriptorCommandsBase607 {608 /// <summary>609 /// Initializes a new instance of the GetAclCommand610 /// class. Sets the default path to the current location.611 /// </summary>612 public GetAclCommand()613 {614 // Default for path is the current location615 _path = new string[] { "." };616 }617 #region parameters618 619 private string[] _path;620 621 /// <summary>622 /// Gets or sets the path of the item for which to obtain the623 /// security descriptor. Default is the current location.624 /// </summary>625 [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]626 [ValidateNotNullOrEmpty]627 public string[] Path628 {629 get630 {631 return _path;632 }633 634 set635 {636 _path = value;637 }638 }639 640 private PSObject _inputObject;641 642 /// <summary>643 /// InputObject Parameter644 /// Gets or sets the inputObject for which to obtain the security descriptor.645 /// </summary>646 [Parameter(Mandatory = true, ParameterSetName = "ByInputObject")]647 public PSObject InputObject648 {649 get650 {651 return _inputObject;652 }653 654 set655 {656 _inputObject = value;657 }658 }659 660 /// <summary>661 /// Gets or sets the literal path of the item for which to obtain the662 /// security descriptor. Default is the current location.663 /// </summary>664 [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]665 [Alias("PSPath", "LP")]666 [ValidateNotNullOrEmpty]667 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]668 public string[] LiteralPath669 {670 get671 {672 return _path;673 }674 675 set676 {677 _path = value;678 _isLiteralPath = true;679 }680 }681 682 private bool _isLiteralPath;683 684 /// <summary>685 /// Gets or sets the audit flag of the command. This flag686 /// determines if audit rules should also be retrieved.687 /// </summary>688 [Parameter]689 public SwitchParameter Audit690 {691 get692 {693 return _audit;694 }695 696 set697 {698 _audit = value;699 }700 }701 702 private SwitchParameter _audit;703 704#if CORECLR705 /// <summary>706 /// Parameter '-AllCentralAccessPolicies' is not supported in OneCore powershell,707 /// because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.708 /// </summary>709 private SwitchParameter AllCentralAccessPolicies710 {711 get; set;712 }713#else714 /// <summary>715 /// Gets or sets the AllCentralAccessPolicies flag of the command. This flag716 /// determines whether the information about all central access policies717 /// available on the machine should be displayed.718 /// </summary>719 [Parameter]720 public SwitchParameter AllCentralAccessPolicies721 {722 get723 {724 return allCentralAccessPolicies;725 }726 727 set728 {729 allCentralAccessPolicies = value;730 }731 }732 733 private SwitchParameter allCentralAccessPolicies;734#endif735 736 #endregion737 738 /// <summary>739 /// Processes records from the input pipeline.740 /// For each input file, the command retrieves its741 /// corresponding security descriptor.742 /// </summary>743 protected override void ProcessRecord()744 {745 AccessControlSections sections =746 AccessControlSections.Owner |747 AccessControlSections.Group |748 AccessControlSections.Access;749 if (_audit)750 {751 sections |= AccessControlSections.Audit;752 }753 754 if (_inputObject != null)755 {756 PSMethodInfo methodInfo = _inputObject.Methods["GetSecurityDescriptor"];757 758 if (methodInfo != null)759 {760 object customDescriptor = null;761 762 try763 {764 customDescriptor = PSObject.Base(methodInfo.Invoke());765 766 if (customDescriptor is not FileSystemSecurity)767 {768 customDescriptor = new CommonSecurityDescriptor(false, false, customDescriptor.ToString());769 }770 }771 catch (Exception)772 {773 // Calling user code, Catch-all OK774 ErrorRecord er =775 SecurityUtils.CreateNotSupportedErrorRecord(776 UtilsStrings.MethodInvokeFail,777 "GetAcl_OperationNotSupported"778 );779 780 WriteError(er);781 return;782 }783 784 WriteObject(customDescriptor, true);785 }786 else787 {788 ErrorRecord er =789 SecurityUtils.CreateNotSupportedErrorRecord(790 UtilsStrings.GetMethodNotFound,791 "GetAcl_OperationNotSupported"792 );793 794 WriteError(er);795 }796 }797 else798 {799 foreach (string p in Path)800 {801 List<string> pathsToProcess = new();802 803 string currentPath = null;804 try805 {806 if (_isLiteralPath)807 {808 pathsToProcess.Add(p);809 }810 else811 {812 Collection<PathInfo> resolvedPaths =813 SessionState.Path.GetResolvedPSPathFromPSPath(p, CmdletProviderContext);814 foreach (PathInfo pi in resolvedPaths)815 {816 pathsToProcess.Add(pi.Path);817 }818 }819 820 foreach (string rp in pathsToProcess)821 {822 currentPath = rp;823 824 CmdletProviderContext context = new(this.Context);825 context.SuppressWildcardExpansion = true;826 827 if (!InvokeProvider.Item.Exists(rp, false, _isLiteralPath))828 {829 ErrorRecord er =830 SecurityUtils.CreatePathNotFoundErrorRecord(831 rp,832 "GetAcl_PathNotFound"833 );834 835 WriteError(er);836 continue;837 }838 839 InvokeProvider.SecurityDescriptor.Get(rp, sections, context);840 841 Collection<PSObject> sd = context.GetAccumulatedObjects();842 if (sd != null)843 {844 AddBrokeredProperties(845 sd,846 _audit,847 AllCentralAccessPolicies);848 WriteObject(sd, true);849 }850 }851 }852 catch (NotSupportedException)853 {854 ErrorRecord er =855 SecurityUtils.CreateNotSupportedErrorRecord(856 UtilsStrings.OperationNotSupportedOnPath,857 "GetAcl_OperationNotSupported",858 currentPath859 );860 861 WriteError(er);862 }863 catch (ItemNotFoundException)864 {865 ErrorRecord er =866 SecurityUtils.CreatePathNotFoundErrorRecord(867 p,868 "GetAcl_PathNotFound_Exception"869 );870 871 WriteError(er);872 continue;873 }874 }875 }876 }877 }878 879 /// <summary>880 /// Defines the implementation of the 'set-acl' cmdlet.881 /// This cmdlet sets the security descriptor of an item at the specified path.882 /// </summary>883 [Cmdlet(VerbsCommon.Set, "Acl", SupportsShouldProcess = true, SupportsTransactions = true, DefaultParameterSetName = "ByPath",884 HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096600")]885 public sealed class SetAclCommand : SecurityDescriptorCommandsBase886 {887 private string[] _path;888 889 /// <summary>890 /// Gets or sets the path of the item for which to set the891 /// security descriptor.892 /// </summary>893 [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]894 public string[] Path895 {896 get897 {898 return _path;899 }900 901 set902 {903 _path = value;904 }905 }906 907 private PSObject _inputObject;908 909 /// <summary>910 /// InputObject Parameter911 /// Gets or sets the inputObject for which to set the security descriptor.912 /// </summary>913 [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByInputObject")]914 public PSObject InputObject915 {916 get917 {918 return _inputObject;919 }920 921 set922 {923 _inputObject = value;924 }925 }926 927 /// <summary>928 /// Gets or sets the literal path of the item for which to set the929 /// security descriptor.930 /// </summary>931 [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]932 [Alias("PSPath", "LP")]933 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]934 public string[] LiteralPath935 {936 get937 {938 return _path;939 }940 941 set942 {943 _path = value;944 _isLiteralPath = true;945 }946 }947 948 private bool _isLiteralPath;949 950 private object _securityDescriptor;951 952 /// <summary>953 /// Gets or sets the security descriptor object to be954 /// set on the target item(s).955 /// </summary>956 [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByPath")]957 [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByLiteralPath")]958 [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByInputObject")]959 public object AclObject960 {961 get962 {963 return _securityDescriptor;964 }965 966 set967 {968 _securityDescriptor = PSObject.Base(value);969 }970 }971 972#if CORECLR973 /// <summary>974 /// Parameter '-CentralAccessPolicy' is not supported in OneCore powershell,975 /// because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.976 /// </summary>977 private string CentralAccessPolicy { get; }978#else979 private string centralAccessPolicy;980 981 /// <summary>982 /// Gets or sets the central access policy to be983 /// set on the target item(s).984 /// </summary>985 [Parameter(Position = 2, Mandatory = false, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]986 [Parameter(Position = 2, Mandatory = false, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]987 public string CentralAccessPolicy988 {989 get990 {991 return centralAccessPolicy;992 }993 994 set995 {996 centralAccessPolicy = value;997 }998 }999#endif1000 1001 private SwitchParameter _clearCentralAccessPolicy;1002 1003 /// <summary>1004 /// Clears the central access policy applied on the target item(s).1005 /// </summary>1006 [Parameter(Mandatory = false, ParameterSetName = "ByPath")]1007 [Parameter(Mandatory = false, ParameterSetName = "ByLiteralPath")]1008 public SwitchParameter ClearCentralAccessPolicy1009 {1010 get1011 {1012 return _clearCentralAccessPolicy;1013 }1014 1015 set1016 {1017 _clearCentralAccessPolicy = value;1018 }1019 }1020 1021 private SwitchParameter _passthru;1022 1023 /// <summary>1024 /// Gets or sets the Passthru flag for the operation.1025 /// If true, the security descriptor is also passed1026 /// down the output pipeline.1027 /// </summary>1028 [Parameter]1029 public SwitchParameter Passthru1030 {1031 get1032 {1033 return _passthru;1034 }1035 1036 set1037 {1038 _passthru = value;1039 }1040 }1041 1042 /// <summary>1043 /// Returns a newly allocated SACL with no ACEs in it.1044 /// Free the returned SACL by calling Marshal.FreeHGlobal.1045 /// </summary>1046 private static IntPtr GetEmptySacl()1047 {1048 IntPtr pSacl = IntPtr.Zero;1049 bool ret = true;1050 1051 try1052 {1053 // Calculate the size of the empty SACL, align to DWORD.1054 uint saclSize = (uint)(Marshal.SizeOf(new NativeMethods.ACL()) +1055 Marshal.SizeOf(new uint()) - 1) & 0xFFFFFFFC;1056 Dbg.Diagnostics.Assert(saclSize < 0xFFFF,1057 "Acl size must be less than max SD size of 0xFFFF");1058 1059 // Allocate and initialize the SACL.1060 pSacl = Marshal.AllocHGlobal((int)saclSize);1061 ret = NativeMethods.InitializeAcl(1062 pSacl,1063 saclSize,1064 NativeMethods.ACL_REVISION);1065 if (!ret)1066 {1067 throw new Win32Exception(Marshal.GetLastWin32Error());1068 }1069 }1070 finally1071 {1072 if (!ret)1073 {1074 Marshal.FreeHGlobal(pSacl);1075 pSacl = IntPtr.Zero;1076 }1077 }1078 1079 return pSacl;1080 }1081 1082 /// <summary>1083 /// Returns a newly allocated SACL with the supplied CAPID in it.1084 /// Free the returned SACL by calling Marshal.FreeHGlobal.1085 /// </summary>1086 /// <remarks>1087 /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.1088 /// So the parameter "-CentralAccessPolicy" is not supported on OneCore powershell,1089 /// and thus this method won't be hit in OneCore powershell.1090 /// </remarks>1091 private IntPtr GetSaclWithCapId(string capStr)1092 {1093 IntPtr pCapId = IntPtr.Zero, pSacl = IntPtr.Zero;1094 IntPtr caps = IntPtr.Zero;1095 bool ret = true, freeCapId = true;1096 uint rs = NativeMethods.STATUS_SUCCESS;1097 1098 try1099 {1100 // Convert the supplied SID from string to binary form.1101 ret = NativeMethods.ConvertStringSidToSid(capStr, out pCapId);1102 if (!ret)1103 {1104 // We may have got a CAP friendly name instead of CAPID.1105 // Enumerate all CAPs on the system and try to find one with1106 // a matching friendly name.1107 // If we retrieve the CAPID from the LSA, the CAPID need not1108 // be deallocated separately (but with the entire buffer1109 // returned by LsaQueryCAPs).1110 freeCapId = false;1111 rs = NativeMethods.LsaQueryCAPs(1112 null,1113 0,1114 out caps,1115 out uint capCount);1116 if (rs != NativeMethods.STATUS_SUCCESS)1117 {1118 throw new Win32Exception((int)rs);1119 }1120 1121 Dbg.Diagnostics.Assert(capCount < 0xFFFF,1122 "Too many central access policies");1123 if (capCount == 0 || caps == IntPtr.Zero)1124 {1125 return IntPtr.Zero;1126 }1127 1128 // Find the supplied string among available CAP names, use the corresponding CAPID.1129 IntPtr capPtr = caps;1130 for (uint capIdx = 0; capIdx < capCount; capIdx++)1131 {1132 Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero,1133 "Invalid central access policies array");1134 NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr);1135 // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.1136 string capName = Marshal.PtrToStringUni(1137 cap.Name.Buffer,1138 cap.Name.Length / 2);1139 if (capName.Equals(capStr, StringComparison.OrdinalIgnoreCase))1140 {1141 pCapId = cap.CAPID;1142 break;1143 }1144 1145 capPtr += Marshal.SizeOf(cap);1146 }1147 }1148 1149 if (pCapId == IntPtr.Zero)1150 {1151 Exception e = new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier);1152 WriteError(new ErrorRecord(1153 e,1154 "SetAcl_CentralAccessPolicy",1155 ErrorCategory.InvalidArgument,1156 AclObject));1157 return IntPtr.Zero;1158 }1159 1160 ret = NativeMethods.IsValidSid(pCapId);1161 if (!ret)1162 {1163 throw new Win32Exception(Marshal.GetLastWin32Error());1164 }1165 1166 uint sidSize = NativeMethods.GetLengthSid(pCapId);1167 1168 // Calculate the size of the SACL with one CAPID ACE, align to DWORD.1169 uint saclSize = (uint)(Marshal.SizeOf(new NativeMethods.ACL()) +1170 Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) +1171 sidSize - 1) & 0xFFFFFFFC;1172 Dbg.Diagnostics.Assert(saclSize < 0xFFFF,1173 "Acl size must be less than max SD size of 0xFFFF");1174 1175 // Allocate and initialize the SACL.1176 pSacl = Marshal.AllocHGlobal((int)saclSize);1177 ret = NativeMethods.InitializeAcl(1178 pSacl,1179 saclSize,1180 NativeMethods.ACL_REVISION);1181 if (!ret)1182 {1183 throw new Win32Exception(Marshal.GetLastWin32Error());1184 }1185 1186 // Add CAPID to the SACL.1187 rs = NativeMethods.AddScopedPolicyIDAce(1188 pSacl,1189 NativeMethods.ACL_REVISION,1190 NativeMethods.SUB_CONTAINERS_AND_OBJECTS_INHERIT,1191 0,1192 pCapId);1193 if (rs != NativeMethods.STATUS_SUCCESS)1194 {1195 if (rs == NativeMethods.STATUS_INVALID_PARAMETER)1196 {1197 throw new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier);1198 }1199 else1200 {