BUG: SQL Server 2005 がネットワーク サービス アカウントで実行されている場合、証明書を使用して暗号化を有効ことはできません。

文書番号: 900495
# をバグ: 374329 (SQLBUDT)
すべて展開する | すべて折りたたむ

現象

Microsoft SQL Server 2005年が、Network Service アカウントで実行されているとき、証明書を使用して暗号化を有効にすることはできません。使用中の暗号化用の証明書を提供する場合は、SQL Server は開始されません。さらに、SQL Server は、エラー ログに次のメッセージことがあります。

日付時間 サーバーがサーバーに必要な証明書を読み込めませんでした。SSL 接続を開始します。次のエラーが返されました: 0x8009030d。チェック証明書を確認するのには有効です。
日付 時間サーバー エラー: 26014、レベル: 16、状態: 1。
日付 時間 サーバーユーザー指定の証明書を読み込むことができません。サーバーは受け付けませんが、接続します。証明書が正しくインストールされていることを確認してください。参照してください。「証明書 SSL を使って本の設定」オンラインにします。

日付時間 サーバー エラー: 17195、レベル: 16、状態: 1。
日付 時間 サーバー暗号化を要求するようにサーバーが構成されているためサーバーは起動できませんがネットワーク ライブラリをサポートすることはできません。暗号化します。
日付 時間サーバー エラー: 17182、レベル: 16、状態: 1。

原因

ネットワーク サービス アカウントにはこの問題が発生します。秘密キー コンテナーの読み取りアクセス許可があるありません。

解決方法

この問題を解決するには、コンパイルおよび .cpp、次を実行します。コードです。

メモ このコードはネットワーク サービスで実行されているすべてのサービスを許可します。コンピューター ストアへのアクセスを考慮します。このコードを慎重に使用します。
/*
	MKACLS - This utility will list the machine key containers present and allow 
	the user to change the key container DACL.
*/

#include <stdio.h>
#include <windows.h>
#include <sddl.h>
#include <aclapi.h>
#include <lm.h>

//Get SD for retrieving DACL.
SECURITY_DESCRIPTOR* GetSecurityDescDacl(HCRYPTPROV hProv) {
 
	SECURITY_DESCRIPTOR *sd;
	unsigned long size = 0;

	CryptGetProvParam(
		hProv,
		PP_KEYSET_SEC_DESCR,
		0,
		&size,
		DACL_SECURITY_INFORMATION);

	int ret = GetLastError();
	if (ret != ERROR_INSUFFICIENT_BUFFER) {
		fprintf(stderr, "Error getting file security DACL: %d\n", ret);
		return 0;
	}

	sd = (SECURITY_DESCRIPTOR *) malloc(size);
	if (! sd) {
		fprintf(stderr, "Out of memory for security descriptor!\n");
		return 0;
	}

	CryptGetProvParam(
		hProv,
		PP_KEYSET_SEC_DESCR,
		(BYTE*)sd,
		&size,
		DACL_SECURITY_INFORMATION);

	return sd;
}

//Get DACL from SD.
ACL* GetDacl(SECURITY_DESCRIPTOR *sd) {
  
	ACL *acl;
	int defaulted, present;

	if (! sd) return 0;

	if (! GetSecurityDescriptorDacl(
		sd, 
		&present, 
		&acl, 
		&defaulted)) 
	{
		fprintf(stderr, "Error getting DACL from security descriptor: %d\n", GetLastError());
		return 0;
	}

	if (! present) {
		fprintf(stderr, "Security descriptor has no DACL present\n");
		free(acl);
		return 0;
	}

	return acl;
}


ACL *AddSidToAcl(const ACL *pOldACL, PSID pSID)
{
	EXPLICIT_ACCESS ea[1] ={{0}};

    // Initialize an EXPLICIT_ACCESS structure for an access control entry.
	ea[0].grfAccessPermissions = FILE_READ_DATA;
	ea[0].grfAccessMode = SET_ACCESS;
	ea[0].grfInheritance= NO_INHERITANCE;
	ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
	ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
	ea[0].Trustee.ptstrName  = (LPTSTR) pSID;

	// Create a new DACL that contains the new access control entries and the old ones.
	
	ACL *pNewACL = NULL;
    DWORD dwRes = SetEntriesInAcl(1, ea, (ACL*)pOldACL, &pNewACL);
	if (ERROR_SUCCESS == dwRes) 
		return pNewACL;

	return NULL;
}


BOOL SetSecurityDescDacl(HCRYPTPROV hProv, const ACL *pACL) 
{
	PSECURITY_DESCRIPTOR pSD = NULL;
	BOOL bRetVal = FALSE;

    // Initialize a security descriptor.  
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); 
    if (NULL == pSD) 
    { 
        printf("LocalAlloc Error %u\n", GetLastError());
        goto CommonReturn; 
    } 
 
    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) 
    {  
        printf("InitializeSecurityDescriptor Error %u\n",GetLastError());
        goto CommonReturn; 
    } 
 
    // Add the DACL to the security descriptor. 
    if (!SetSecurityDescriptorDacl(pSD, 
            TRUE,   
            (ACL*)pACL, 
            FALSE)) 
    {  
        printf("SetSecurityDescriptorDacl Error %u\n", GetLastError());
        goto CommonReturn; 
    } 

	if(!CryptSetProvParam(
		hProv,
		PP_KEYSET_SEC_DESCR,
		(BYTE*)pSD,
		DACL_SECURITY_INFORMATION))
	{
		printf("CryptSetProvParam failed, lasterror = 0x%08x\n", GetLastError());
		goto CommonReturn;
	}

	bRetVal = TRUE;

CommonReturn:
	if (pSD)
		LocalFree(pSD);

	return bRetVal;
}




PSID GetSIDForAccount(LPCSTR pszAcct)
{
	PSID	pSID = NULL;
	DWORD	cbSID = 0;
	DWORD   cbDomain = 0;
	LPTSTR  pszDomain = NULL;
	SID_NAME_USE snu;
	

	LookupAccountName(NULL, pszAcct, NULL, &cbSID, NULL, &cbDomain, &snu);

	if ( cbSID )
	{
		pSID = (PSID)malloc(cbSID);
		pszDomain = (LPTSTR)malloc(cbDomain);

		if ( pSID && pszDomain)
		{
			if ( LookupAccountName(NULL, pszAcct, pSID, &cbSID, pszDomain, &cbDomain, &snu) )
			{
				// Success. Therefore, kill the domain buffer that we do not need.
				free(pszDomain);
				pszDomain = NULL;
			}
			else
			{
				// Failed. Therefore, kill both buffers.
				free(pszDomain);
				pszDomain = NULL;
				free(pSID);
				pSID = NULL;
			}
		}
	}

	return pSID;
}

BOOL ChangeContainerACL(LPCSTR pszContainer)
{
	HCRYPTPROV hProv = 0;
	BOOL bRetVal = FALSE;

	if(CryptAcquireContext(&hProv,
							pszContainer,
							MS_DEF_PROV,
							PROV_RSA_FULL,
							CRYPT_MACHINE_KEYSET))
	{

		SECURITY_DESCRIPTOR *pSD = GetSecurityDescDacl(hProv);
		if (pSD)
		{
			ACL *pCurACL = GetDacl(pSD);
			if (pCurACL)
			{
				//TODO: This should be replaced with a call to RtlCreateServiceSid for LH.
				PSID pSID = GetSIDForAccount("NetworkService");

				if ( pSID)
				{
					ACL *pNewACL = AddSidToAcl(pCurACL, pSID);
					if ( pNewACL )
					{
						bRetVal = SetSecurityDescDacl(hProv, pNewACL);
						LocalFree(pNewACL);
					}

					free(pSID);
				}

				LocalFree(pCurACL);
			}
			free(pSD);
		}

		CryptReleaseContext(hProv, 0);
	}
	else
		printf("Error opening key container %s\n", pszContainer);
		 
	return bRetVal;
}

int __cdecl main()
{ 
	HCRYPTPROV hProv= 0;	

	printf("Looking for CAPI machine key containers...\n");

	if(CryptAcquireContext(&hProv,
							NULL,
							MS_DEF_PROV,
							PROV_RSA_FULL,
							CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET))
	{

		for (int i=0 ; ; i++) 
		{
			DWORD dwFlags = i ? 0 : CRYPT_FIRST;
			const DWORD BUFLEN = 4096;
			DWORD dwBufLen = BUFLEN;
			BYTE szBuf[BUFLEN];

			if(!CryptGetProvParam(hProv, PP_ENUMCONTAINERS, szBuf, &dwBufLen, dwFlags)) 
			{
				DWORD dwError = GetLastError();
				if( dwError != ERROR_NO_MORE_ITEMS && dwError != ERROR_FILE_NOT_FOUND)
		            printf("Error reading container name - %08x\n", GetLastError());
				break;
			}
			else
			{
				if ( !ChangeContainerACL((LPCSTR)szBuf) )
					printf("Error changing ACL on container %s\n", szBuf);
				else
					printf("Changed ACL on container %s\n", szBuf);
			}
			
		}

		CryptReleaseContext(hProv,0);
	}
	else
		printf("Error opening CSP - %08x\n", GetLastError());

	printf("Done\n");

	return 0;
}
このコードが秘密キーを読み取るため、ネットワーク サービス アカウントのアクセス許可を付与します。コンテナー。このコードを実行、次のメッセージには、SQL Server ことがあります。SQL Server を起動するとエラーのログ:

日付時間 サーバーの証明書が正常に読み込まれました暗号化します。

状況

Microsoft では、この「対象」に記載されているマイクロソフト製品のバグとして認識しています。

プロパティ

文書番号: 900495 - 最終更新日: 2011年8月3日 - リビジョン: 6.0
キーワード:?
kbtshoot kbprb kbcode kbmt KB900495 KbMtja
機械翻訳の免責
重要: このサポート技術情報 (以下「KB」) は、翻訳者による翻訳の代わりに、マイクロソフト機械翻訳システムによって翻訳されたものです。マイクロソフトは、お客様に、マイクロソフトが提供している全ての KB を日本語でご利用いただけるように、翻訳者による翻訳 KB に加え機械翻訳 KB も提供しています。しかしながら、機械翻訳の品質は翻訳者による翻訳ほど十分ではありません。誤訳や、文法、言葉使い、その他、たとえば日本語を母国語としない方が日本語を話すときに間違えるようなミスを含んでいる可能性があります。マイクロソフトは、機械翻訳の品質、及び KB の内容の誤訳やお客様が KB を利用されたことによって生じた直接または間接的な問題や損害については、いかなる責任も負わないものとします。マイクロソフトは、機械翻訳システムの改善を継続的に行っています。
英語版 KB:900495
Microsoft Knowledge Base の免責: Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。

フィードバック