WIn32API Windowsサービスのセキュリティ情報を取得する QueryServiceObjectSecurity

Windowsサービスは、プロセスやファイルなどと同様にセキュリティ記述子を持っている。そして、このセキュリティ記述子は、QueryServiceObjectSecurity関数で取得することが可能である。


QueryServiceObjectSecurity関数のプロトタイプは、以下のとおり。

BOOL QueryServiceObjectSecurity(
  SC_HANDLE hService,      // サービスのハンドル
  SECURITY_INFORMATION dwSecurityInformation,
 // 取得するセキュリティ情報のタイプ
  PSECURITY_DESCRIPTOR lpSecurityDescriptor,
 // セキュリティ記述子のアドレス
  DWORD cbBufSize,         // セキュリティ記述子を保持するバッファのサイズ
  LPDWORD pcbBytesNeeded   // 必要なバイト数を受け取る変数のアドレス
);


 以下のプログラムは、DHCPサービスのセキュリティ情報を取得して表示している。

 まず、OpenSCManager関数、OpenService関数でサービスのハンドルを取得し、そのサービスのハンドルを第1引数に指定してQueryServiceObjectSecurity関数を呼び出すことで、サービスのセキュリティ記述子を取得している。

 その後は、GetSecurityDescriptorDacl関数でDACL(随意アクセス制御リスト)を取得し、GetAce関数でDACLからACE(アクセス制御エントリ)を取得し、各ACEのアカウント名、ドメイン名、アクセスマスクを取得し表示している。ACEのアカウント名、ドメイン名はLookupAccountSid関数で取得している。

#include <windows.h>
#include <stdio.h>
#include <locale.h>

int main()
{
    SC_HANDLE hSCM = NULL;
    SC_HANDLE hService = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    DWORD dwBytesNeeded;
    BOOL bDaclPresent;
    BOOL bDaclDefaulted;
    PACL pDacl;
    ACL_SIZE_INFORMATION aclSize;
    ACCESS_ALLOWED_ACE *pAce;
    TCHAR szAccountName[256];
    TCHAR szDomainName[256];
    DWORD dwAccountNameSize;
    DWORD dwDomainNameSize;
    SID_NAME_USE snu;
    DWORD i;
    LPCTSTR lpszServiceName = TEXT("Dhcp");

    setlocale(LC_ALL, setlocale(LC_CTYPE, ""));//コンソールに日本語を表示させるため

    //サービス制御マネージャーのハンドルを取得
    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (hSCM == NULL) {
        printf("OpenSCManager error: %d\n", GetLastError());
        goto EXIT_FUNC;
    }

    //サービスのハンドルを取得
    hService = OpenService(hSCM,
        lpszServiceName,
        READ_CONTROL);

    if (hService == NULL) {
        printf("OpenService error: %d\n", GetLastError());
        goto EXIT_FUNC;
    }

    //サービスのセキュリティ記述子を格納するのに必要なメモリサイズをdwBytesNeededに取得する
    QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, NULL, 0, &dwBytesNeeded);

    pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwBytesNeeded);
    if (pSD == NULL) {
        goto EXIT_FUNC;
    }


    //サービスのセキュリティ記述子をpSDに取得する
    QueryServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, pSD, dwBytesNeeded, &dwBytesNeeded);

    //サービスのセキュリティ記述子からpDaclにDACL(随意アクセス制御リスト)を取得する
    GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted);

    if (!bDaclPresent) {
        puts("No Dacl");
    } else {
        
        GetAclInformation(pDacl, &aclSize, sizeof(aclSize), AclSizeInformation);
        
        for (i = 0; i < aclSize.AceCount; i++) {

            //DACLからACEを取得する
            GetAce(pDacl, i, (LPVOID *)&pAce);

            dwAccountNameSize = sizeof(szAccountName)/sizeof(szAccountName[0]);
            dwDomainNameSize = sizeof(szDomainName)/sizeof(szDomainName[0]);

            //SIDからACEのアカウント、ドメイン名を取得する
            LookupAccountSid(NULL,
                &pAce->SidStart,
                szAccountName,
                &dwAccountNameSize,
                szDomainName,
                &dwDomainNameSize,
                &snu);

            puts("======================================================================");
            _tprintf(TEXT("AccountName: %s\n"), szAccountName);
            _tprintf(TEXT("DomainName: %s\n"), szDomainName);

            puts("\n==========  AccessMask  ==========");
            
            if ( (pAce->Mask & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG )
                puts("SERVICE_QUERY_CONFIG");
            if ( (pAce->Mask & SERVICE_CHANGE_CONFIG) == SERVICE_CHANGE_CONFIG )
                puts("SERVICE_CHANGE_CONFIG");
            if ( (pAce->Mask & SERVICE_QUERY_STATUS) == SERVICE_QUERY_STATUS ) 
                puts("SERVICE_QUERY_STATUS");
            if ( (pAce->Mask & SERVICE_START) == SERVICE_START )
                puts("SERVICE_START");
            if ( (pAce->Mask & SERVICE_STOP) == SERVICE_STOP ) 
                puts("SERVICE_STOP");
            if ( (pAce->Mask & SERVICE_PAUSE_CONTINUE) == SERVICE_PAUSE_CONTINUE )
                puts("SERVICE_PAUSE_CONTINUE");
            if ( (pAce->Mask & SERVICE_INTERROGATE) == SERVICE_INTERROGATE ) 
                puts("SERVICE_INTERROGATE");
            if ( (pAce->Mask & SERVICE_USER_DEFINED_CONTROL) == SERVICE_USER_DEFINED_CONTROL )
                puts("SERVICE_USER_DEFINED_CONTROL");
        
            puts("\n");
        }

    }


EXIT_FUNC:

    LocalFree(pSD);
    CloseServiceHandle(hSCM);
    CloseServiceHandle(hService);

    return 0;
}



  • 実行結果
  • ======================================================================
    AccountName: Authenticated Users
    DomainName: NT AUTHORITY
    
    ==========  AccessMask  ==========
    SERVICE_QUERY_CONFIG
    SERVICE_QUERY_STATUS
    SERVICE_INTERROGATE
    SERVICE_USER_DEFINED_CONTROL
    
    
    ======================================================================
    AccountName: Authenticated Users
    DomainName: NT AUTHORITY
    
    ==========  AccessMask  ==========
    SERVICE_QUERY_CONFIG
    SERVICE_QUERY_STATUS
    SERVICE_START
    SERVICE_STOP
    SERVICE_PAUSE_CONTINUE
    SERVICE_INTERROGATE
    SERVICE_USER_DEFINED_CONTROL
    
    
    ======================================================================
    AccountName: Administrators
    DomainName: BUILTIN
    
    ==========  AccessMask  ==========
    SERVICE_QUERY_CONFIG
    SERVICE_CHANGE_CONFIG
    SERVICE_QUERY_STATUS
    SERVICE_START
    SERVICE_STOP
    SERVICE_PAUSE_CONTINUE
    SERVICE_INTERROGATE
    SERVICE_USER_DEFINED_CONTROL
    
    
    ======================================================================
    AccountName: コンソール ログオン
    DomainName:
    
    ==========  AccessMask  ==========
    SERVICE_QUERY_CONFIG
    SERVICE_QUERY_STATUS
    SERVICE_START
    SERVICE_INTERROGATE
    SERVICE_USER_DEFINED_CONTROL
    
    
    ======================================================================
    AccountName: SYSTEM
    DomainName: NT AUTHORITY
    
    ==========  AccessMask  ==========
    SERVICE_QUERY_CONFIG
    SERVICE_QUERY_STATUS
    SERVICE_START
    SERVICE_STOP
    SERVICE_PAUSE_CONTINUE
    SERVICE_INTERROGATE
    SERVICE_USER_DEFINED_CONTROL
    


  • 参考

  • http://msdn.microsoft.com/ja-jp/library/cc447525.aspx