potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C++20&Win API ファイルセキュリティオーナーの名前・参照ドメイン名・名前の使い方を取得する

一部のC APIC++ラッパーを作成しています。

#include <string>
#include <vector>

#define STRICT
#define NOMINMAX
#include <Windows.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の名前・参照ドメイン名・名前の使い方を返します。
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);
}

int main()
{
    std::wstring_view path{ L"C:\\Windows" };

    // ファイルのオーナーセキュリティ情報を取得します。
    auto secDescBuffer = GetFileSecurityW(path, OWNER_SECURITY_INFORMATION);
    auto pSecDesc = static_cast<PSECURITY_DESCRIPTOR>(secDescBuffer.data());

    // オーナーのSIDとSE_OWNER_DEFAULTEDフラグの有無を取得します。
    PSID psidOwner;
    BOOL ownerDefaulted;
    if (!::GetSecurityDescriptorOwner(pSecDesc, &psidOwner, &ownerDefaulted))
    {
        return 0;
    }

    // オーナーの名前・参照ドメイン名・名前の使い方を取得します。
    auto [name, refDomainName, use] = LookupAccountSidW({}, psidOwner);

    return 0;
}