ファイルセキュリティ記述子→DACL→ACEと取得してセキュリティユーザーの名前を列挙するサンプルです。
#include <bit> #include <string> #include <span> #include <memory> #include <vector> #define STRICT #define NOMINMAX #include <Windows.h> #include <AclAPI.h> // ファイルのセキュリティ情報をバイト配列として返します。 std::vector<BYTE> GetFileSecurityW(std::wstring_view Path, SECURITY_INFORMATION RequestedInformation) { DWORD needed{ 0 }; if (!::GetFileSecurityW(Path.data(), RequestedInformation, nullptr, 0, &needed) && ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { return {}; } std::vector<BYTE> buffer(needed); if (!::GetFileSecurityW(Path.data(), RequestedInformation, static_cast<PSECURITY_DESCRIPTOR>(buffer.data()), needed, &needed)) { return {}; } return std::move(buffer); } // SIDの名前・参照ドメイン名・名前の使い方を返します。 // auto [name, refDomainName, use] = LookupAccountSidW(SystemName, Sid); std::tuple<std::wstring, std::wstring, SID_NAME_USE> LookupAccountSidW( std::wstring_view SystemName, PSID Sid) { DWORD cchName{ 0 }; DWORD cchRefDomainName{ 0 }; SID_NAME_USE use; if (!::LookupAccountSidW(nullptr, Sid, 0, &cchName, nullptr, &cchRefDomainName, &use) && ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { return {}; } std::wstring name(cchName, L'\0'); std::wstring refDomainName(cchRefDomainName, L'\0'); if (!::LookupAccountSidW(nullptr, Sid, name.data(), &cchName, refDomainName.data(), &cchRefDomainName, &use)) { return {}; } return std::make_tuple(std::move(name), std::move(refDomainName), use); } struct HLOCAL_deleter { void operator() (void* p) const noexcept { ::LocalFree(p); } }; template <typename T> using unique_hlocal_ptr = std::unique_ptr<T, HLOCAL_deleter>; using unique_EXPLICIT_ACCESS_W = unique_hlocal_ptr<EXPLICIT_ACCESS_W>; // ACLのACE記述構造体配列を取得します。 // auto [p, entryCount, explicitEntries] = GetExplicitEntriesFromAclWInUniquePtr(pDacl); std::tuple<unique_EXPLICIT_ACCESS_W, ULONG, std::span<EXPLICIT_ACCESS_W>> GetExplicitEntriesFromAclWInUniquePtr( PACL pAcl) { ULONG entryCount; PEXPLICIT_ACCESS_W pExplicitEntries; if (::GetExplicitEntriesFromAclW(pAcl, &entryCount, &pExplicitEntries) != ERROR_SUCCESS) { return {}; } return std::make_tuple( unique_EXPLICIT_ACCESS_W(pExplicitEntries), entryCount, std::span{ pExplicitEntries, pExplicitEntries + entryCount }); } // TRUSTEE_W構造体から名前を取得します。 std::wstring GetTrusteeName(const TRUSTEE_W& Trustee) { // https://docs.microsoft.com/en-us/windows/win32/api/accctrl/ns-accctrl-trustee_a // TRUSTEE_IS_NAME/TRUSTEE_IS_OBJECTS_AND_NAME/TRUSTEE_IS_OBJECTS_AND_SID/TRUSTEE_IS_SID switch (Trustee.TrusteeForm) { case TRUSTEE_IS_NAME: return Trustee.ptstrName; case TRUSTEE_IS_OBJECTS_AND_NAME: return std::bit_cast<OBJECTS_AND_NAME_W*>(Trustee.ptstrName)->ptstrName; case TRUSTEE_IS_OBJECTS_AND_SID: { auto [name, refDomainName, use] = LookupAccountSidW( {}, std::bit_cast<OBJECTS_AND_SID*>(Trustee.ptstrName)->pSid); return std::move(name); } break; case TRUSTEE_IS_SID: { auto [name, refDomainName, use] = LookupAccountSidW( {}, std::bit_cast<PSID>(Trustee.ptstrName)); return std::move(name); } default: return {}; } } #include <iostream> int main() { std::wstring_view path{ L"C:\\Windows" }; // ファイルのDACLセキュリティ情報を取得します。 auto secDescBuffer = GetFileSecurityW(path, DACL_SECURITY_INFORMATION); auto pSecDesc = static_cast<PSECURITY_DESCRIPTOR>(secDescBuffer.data()); // ファイルのDACLの存在・ポインタ・既定かどうかを取得します。 BOOL daclPresent; PACL pDacl; BOOL daclDefaulted; if (!::GetSecurityDescriptorDacl(pSecDesc, &daclPresent, &pDacl, &daclDefaulted)) { return 0; } // DACLのエントリを取得します。 auto [p, entryCount, explicitEntries] = GetExplicitEntriesFromAclWInUniquePtr(pDacl); for (auto& explicitEntry : explicitEntries) { std::wcout << GetTrusteeName(explicitEntry.Trustee) << std::endl; } return 0; }