BUG: Non è possibile abilitare la crittografia utilizzando un certificato quando SQL Server 2005 è in esecuzione con l'account servizio di rete

BUG #: 374329 (SQLBUDT)

Sintomi

Se Microsoft SQL Server 2005 è in esecuzione con l'account servizio di rete, è possibile attivare la crittografia utilizzando un certificato. Se viene effettuato il provisioning di un certificato per l'utilizzo della crittografia, SQL Server non verrà avviato. Inoltre, è possibile notare il seguente messaggio nel log degli errori di SQL Server:


Data Ora Server il server non è riuscito a caricare il certificato che necessario avviare una connessione SSL. Restituito il seguente errore: 0x8009030d. Controllare i certificati per verificare che siano valide.
DataOra Errore del server: 26014, gravità: 16, stato: 1.

DataOra Server Impossibile caricare il certificato specificato dall'utente. Il server non accetterà una connessione. È necessario verificare che il certificato sia installato correttamente. Vedere "Configurazione dei certificati per l'utilizzo da SSL" nella documentazione in linea.

DataOra Errore del server: 17195, gravità: 16, stato: 1.

DataOra Server di server non avvio perché il server è configurato per richiedere la crittografia, ma le librerie di rete non è in grado di supportare la crittografia.
DataOra Errore del server: 17182, gravità: 16, stato: 1.

Causa

Questo problema si verifica perché l'account del servizio di rete non dispone delle autorizzazioni per leggere i contenitori di chiavi private.

Risoluzione

Per risolvere questo problema, compilare ed eseguire il codice riportato di seguito. cpp.

Nota: Questo codice autorizza tutti i servizi in esecuzione con l'account Network Service l'accesso all'archivio computer. Utilizzare questo codice con discrezione.

/*
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)
{
PSIDpSID = NULL;
DWORDcbSID = 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;
}

Questo codice vengono concesse le autorizzazioni di account di servizio di rete per leggere i contenitori di chiavi private. Dopo aver eseguito questo codice, è possibile notare il seguente messaggio nel log degli errori di SQL Server quando si avvia SQL Server:


Data Ora Il certificato è stato caricato per la crittografia di server.

Stato

Microsoft ha confermato che si tratta di un bug nei prodotti Microsoft elencati nella sezione "Si applica a".

Serve aiuto?

Amplia le tue competenze
Esplora i corsi di formazione
Ottieni in anticipo le nuove caratteristiche
Partecipa a Microsoft Insider

Queste informazioni sono risultate utili?

Grazie per il feedback!

Grazie per il tuo feedback! Potrebbe essere utile metterti in contatto con uno dei nostri operatori del supporto di Office.

×