/// <summary> /// Gets the central access policy name of the provided PSObject. /// </summary> /// <remarks> /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer. /// </remarks> /// <param name="instance"> /// The PSObject for which to obtain the central access policy name. /// </param> /// <returns> /// The central access policy name of the provided PSObject. /// </returns> public static string GetCentralAccessPolicyName(PSObject instance) { SecurityIdentifier capId = GetCentralAccessPolicyId(instance); if (capId == null) { return null; // file does not have the scope ace } int capIdSize = capId.BinaryLength; byte[] capIdArray = new byte[capIdSize]; capId.GetBinaryForm(capIdArray, 0); IntPtr caps = IntPtr.Zero; IntPtr pCapId = Marshal.AllocHGlobal(capIdSize); try { // Retrieve the CAP by CAPID. Marshal.Copy(capIdArray, 0, pCapId, capIdSize); IntPtr[] ppCapId = new IntPtr[1]; ppCapId[0] = pCapId; uint capCount = 0; uint rs = NativeMethods.LsaQueryCAPs( ppCapId, 1, out caps, out capCount); if (rs != NativeMethods.STATUS_SUCCESS) { throw new Win32Exception((int)rs); } if (capCount == 0 || caps == IntPtr.Zero) { return null; } // Get the CAP name. NativeMethods.CENTRAL_ACCESS_POLICY cap = new NativeMethods.CENTRAL_ACCESS_POLICY(); cap = ClrFacade.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(caps); // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes. return Marshal.PtrToStringUni(cap.Name.Buffer, cap.Name.Length / 2); } finally { Marshal.FreeHGlobal(pCapId); uint rs = NativeMethods.LsaFreeMemory(caps); Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS, "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture)); } }
/// <summary> /// Gets the names and IDs of all central access policies available on the machine. /// </summary> /// <remarks> /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer. /// </remarks> /// <param name="instance"> /// The PSObject argument is ignored. /// </param> /// <returns> /// The names and IDs of all central access policies available on the machine. /// </returns> public static string[] GetAllCentralAccessPolicies(PSObject instance) { IntPtr caps = IntPtr.Zero; try { // Retrieve all CAPs. uint capCount = 0; uint rs = NativeMethods.LsaQueryCAPs( null, 0, out caps, out capCount); if (rs != NativeMethods.STATUS_SUCCESS) { throw new Win32Exception((int)rs); } Dbg.Diagnostics.Assert(capCount < 0xFFFF, "Too many central access policies"); if (capCount == 0 || caps == IntPtr.Zero) { return null; } // Add CAP names and IDs to a string array. string[] policies = new string[capCount]; NativeMethods.CENTRAL_ACCESS_POLICY cap = new NativeMethods.CENTRAL_ACCESS_POLICY(); IntPtr capPtr = caps; for (uint capIdx = 0; capIdx < capCount; capIdx++) { // Retrieve CAP name. Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero, "Invalid central access policies array"); cap = ClrFacade.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr); // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes. policies[capIdx] = "\"" + Marshal.PtrToStringUni( cap.Name.Buffer, cap.Name.Length / 2) + "\""; // Retrieve CAPID. IntPtr pCapId = cap.CAPID; Dbg.Diagnostics.Assert(pCapId != IntPtr.Zero, "Invalid central access policies array"); bool ret = NativeMethods.IsValidSid(pCapId); if (!ret) { throw new Win32Exception(Marshal.GetLastWin32Error()); } SecurityIdentifier sid = new SecurityIdentifier(pCapId); policies[capIdx] += " (" + sid.ToString() + ")"; capPtr += Marshal.SizeOf(cap); } return policies; } finally { uint rs = NativeMethods.LsaFreeMemory(caps); Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS, "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture)); } }
/// <summary> /// Returns a newly allocated SACL with the supplied CAPID in it. /// Free the returned SACL by calling Marshal.FreeHGlobal. /// </summary> /// <remarks> /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer. /// So the parameter "-CentralAccessPolicy" is not supported on OneCore powershell, /// and thus this method won't be hit in OneCore powershell. /// </remarks> private IntPtr GetSaclWithCapId(string capStr) { IntPtr pCapId = IntPtr.Zero, pSacl = IntPtr.Zero; IntPtr caps = IntPtr.Zero; bool ret = true, freeCapId = true; uint rs = NativeMethods.STATUS_SUCCESS; try { // Convert the supplied SID from string to binary form. ret = NativeMethods.ConvertStringSidToSid(capStr, out pCapId); if (!ret) { // We may have got a CAP friendly name instead of CAPID. // Enumerate all CAPs on the system and try to find one with // a matching friendly name. // If we retrieve the CAPID from the LSA, the CAPID need not // be deallocated separately (but with the entire buffer // returned by LsaQueryCAPs). freeCapId = false; uint capCount = 0; rs = NativeMethods.LsaQueryCAPs( null, 0, out caps, out capCount); if (rs != NativeMethods.STATUS_SUCCESS) { throw new Win32Exception((int)rs); } Dbg.Diagnostics.Assert(capCount < 0xFFFF, "Too many central access policies"); if (capCount == 0 || caps == IntPtr.Zero) { return IntPtr.Zero; } // Find the supplied string among available CAP names, use the corresponding CAPID. NativeMethods.CENTRAL_ACCESS_POLICY cap = new NativeMethods.CENTRAL_ACCESS_POLICY(); IntPtr capPtr = caps; for (uint capIdx = 0; capIdx < capCount; capIdx++) { Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero, "Invalid central access policies array"); cap = ClrFacade.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr); // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes. string capName = Marshal.PtrToStringUni( cap.Name.Buffer, cap.Name.Length / 2); if (capName.Equals(capStr, StringComparison.OrdinalIgnoreCase)) { pCapId = cap.CAPID; break; } capPtr += Marshal.SizeOf(cap); } } if (pCapId == IntPtr.Zero) { Exception e = new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier); WriteError(new ErrorRecord( e, "SetAcl_CentralAccessPolicy", ErrorCategory.InvalidArgument, AclObject)); return IntPtr.Zero; } ret = NativeMethods.IsValidSid(pCapId); if (!ret) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint sidSize = NativeMethods.GetLengthSid(pCapId); // Calculate the size of the SACL with one CAPID ACE, align to DWORD. uint saclSize = (uint)(Marshal.SizeOf(new NativeMethods.ACL()) + Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) + sidSize - 1) & 0xFFFFFFFC; Dbg.Diagnostics.Assert(saclSize < 0xFFFF, "Acl size must be less than max SD size of 0xFFFF"); // Allocate and initialize the SACL. pSacl = Marshal.AllocHGlobal((int)saclSize); ret = NativeMethods.InitializeAcl( pSacl, saclSize, NativeMethods.ACL_REVISION); if (!ret) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // Add CAPID to the SACL. rs = NativeMethods.RtlAddScopedPolicyIDAce( pSacl, NativeMethods.ACL_REVISION, NativeMethods.SUB_CONTAINERS_AND_OBJECTS_INHERIT, 0, pCapId); if (rs != NativeMethods.STATUS_SUCCESS) { if (rs == NativeMethods.STATUS_INVALID_PARAMETER) { throw new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier); } else { throw new Win32Exception((int)rs); } } } finally { if (!ret || rs != NativeMethods.STATUS_SUCCESS) { Marshal.FreeHGlobal(pSacl); pSacl = IntPtr.Zero; } rs = NativeMethods.LsaFreeMemory(caps); Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS, "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture)); if (freeCapId) { NativeMethods.LocalFree(pCapId); } } return pSacl; }