SQL Server 인증 사용자 암호 변경(OLE DB)

이 예제에서는 OLE DB를 사용하여 SQL Server 인증이 적용되는 사용자 계정의 암호를 변경하는 방법을 보여 줍니다.

보안 정보보안 정보

가능하면 Windows 인증을 사용하십시오. Windows 인증을 사용할 수 없으면 런타임에 사용자에게 자격 증명을 입력하라는 메시지를 표시합니다. 자격 증명은 파일에 저장하지 않는 것이 좋습니다. 자격 증명을 유지하려면 Win32 crypto API를 사용하여 자격 증명을 암호화해야 합니다.

빌드하기 전에 .C++ 코드를 업데이트하여 사용자 ID, 이전 암호 및 새 암호를 지정합니다.

이 응용 프로그램은 컴퓨터의 기본 SQL Server 인스턴스에 연결됩니다. 일부 Windows 운영 체제에서는 (localhost) 또는 (local)을 해당 SQL Server 인스턴스의 이름으로 변경해야 합니다. 명명된 인스턴스에 연결하려면 연결 문자열을 L"(local)"에서 L"(local)\\name"으로 변경합니다. 여기서 name은 명명된 인스턴스입니다. 기본적으로 SQL Server Express는 명명된 인스턴스에 설치됩니다. INCLUDE 환경 변수에 sqlncli.h가 들어 있는 디렉터리를 포함해야 합니다.

ole32.lib oleaut32.lib를 사용하여 컴파일합니다.

이 예제를 빌드하려면 암호를 알고 있는 SQL Server 인증 사용자 계정이 필요합니다. SQL Server 인증으로 로그인할 수 있게 하려면 SQL Server Management Studio를 열고 개체 탐색기에서 서버 노드를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 보안을 선택하고 SQL Server 및 Windows 인증 모드를 활성화합니다. SQL Server 인증이 적용되는 사용자 계정을 추가하려면 개체 탐색기에서 보안 노드를 마우스 오른쪽 단추로 클릭하고 추가를 선택합니다.

이 예제를 실행할 서버에는 SQL Server 인증용으로 활성화된 로그인이 최소한 하나 이상 있어야 합니다. 또한 SQL Server 인증 로그인을 허용하도록 서버를 설정해야 합니다.

// compile with: ole32.lib oleaut32.lib
void InitializeAndEstablishConnection();

#define STATUSDUMP(status)  case status : wprintf(L"status"); break;

#define UNICODE
#define DBINITCONSTANTS
#define INITGUID

#include <assert.h>
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <IOSTREAM>
#include <cguid.h>
#include <oledb.h>
#include <oledberr.h>

#include <SQLNCLI.h>

LPMALLOC pMalloc = NULL;
IDBInitialize * pIDBInitialize = NULL;
HRESULT hr;

void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError);
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, BOOL &has_sql_errors);

int main() {
   // All the initialization activities in a separate function.
   InitializeAndEstablishConnection();

   if ( FAILED( pIDBInitialize->Uninitialize() ) )
      // Uninitialize is not required, but fails if an interface was not released.
      printf("Problem uninitializing.\n");

   pIDBInitialize->Release();
   CoUninitialize();
};

void InitializeAndEstablishConnection() {
   IDBProperties * pIDBProperties = NULL;
   const ULONG nInitProps = 4;
   DBPROP InitProperties[nInitProps];
   const ULONG nSSInitProps = 1;
   DBPROP SSInitProperties[nSSInitProps];

   const ULONG nPropSet = 2;
   DBPROPSET rgInitPropSet[nPropSet];

   // Initialize the COM library.
   CoInitialize(NULL);
   CoGetMalloc(1, &pMalloc);

   CLSID clsid;
   CLSIDFromProgID(L"SQLNCLI11", &clsid);

   // Obtain access to the SQLOLEDB provider.
   hr = CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize);
   if (FAILED(hr))
      printf("Failed in CoCreateInstance().\n");

   // Initialize the property values needed to establish the connection.
   for (int i = 0; i < nInitProps; i++)
      VariantInit(&InitProperties[i].vValue);

   // Specify database name.
   InitProperties[0].dwPropertyID = DBPROP_INIT_CATALOG;
   InitProperties[0].vValue.vt = VT_BSTR;
   // Change the following line to use any database on your server
   InitProperties[0].vValue.bstrVal = SysAllocString(L"master");
   InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
   InitProperties[0].colid = DB_NULLID;

   InitProperties[1].dwPropertyID = DBPROP_AUTH_USERID;
   InitProperties[1].vValue.vt = VT_BSTR;
   // Modify the following line to add the user ID of a SQL Server Authentication account on your server
   InitProperties[1].vValue.bstrVal = SysAllocString(L"");
   InitProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;
   InitProperties[1].colid = DB_NULLID;

   InitProperties[2].dwPropertyID = DBPROP_AUTH_PASSWORD;
   InitProperties[2].vValue.vt = VT_BSTR;
   // Modify the following line to add the new SQL Server Authentication password
   InitProperties[2].vValue.bstrVal = SysAllocString(L"");
   InitProperties[2].dwOptions = DBPROPOPTIONS_REQUIRED;
   InitProperties[2].colid = DB_NULLID;

   InitProperties[3].dwPropertyID = DBPROP_INIT_DATASOURCE;
   InitProperties[3].vValue.vt = VT_BSTR;
   InitProperties[3].vValue.bstrVal = SysAllocString(L"(local)");
   InitProperties[3].dwOptions = DBPROPOPTIONS_REQUIRED;
   InitProperties[3].colid = DB_NULLID;

   SSInitProperties[0].dwPropertyID = SSPROP_AUTH_OLD_PASSWORD;
   SSInitProperties[0].vValue.vt = VT_BSTR;
   // Modify the following line to specify the existing SQL Server Authentication password
   SSInitProperties[0].vValue.bstrVal = SysAllocString(L"");
   SSInitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
   SSInitProperties[0].colid = DB_NULLID;

   rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
   rgInitPropSet[0].cProperties = nInitProps;
   rgInitPropSet[0].rgProperties = InitProperties;

   rgInitPropSet[1].guidPropertySet = DBPROPSET_SQLSERVERDBINIT;
   rgInitPropSet[1].cProperties = nSSInitProps;
   rgInitPropSet[1].rgProperties = SSInitProperties;

   // Set initialization properties.
   hr = pIDBInitialize->QueryInterface( IID_IDBProperties, (void **)&pIDBProperties);

   if (FAILED(hr))
      printf("Failed to obtain IDBProperties interface.\n");

   hr = pIDBProperties->SetProperties( nPropSet, rgInitPropSet);

   if (FAILED(hr))
      printf("Failed to set initialization properties.\n");

   pIDBProperties->Release();

   // establish connection to the data source.
   DWORD now = GetTickCount();

   if ( FAILED(pIDBInitialize->Initialize()) ) {
      printf("Problem in initializing.\n");
      DumpErrorInfo(pIDBInitialize, IID_IDBInitialize);
   }

   DWORD tookms = GetTickCount() - now;
   printf("Connection took %d ms.\n", tookms);
}

// DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available status
// or error information. This version is called when SQL Server errors are not expected.
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError) {
   BOOL has_sql_errors;
   DumpErrorInfo (pObjectWithError, IID_InterfaceWithError, has_sql_errors);
}

// DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available status 
// or error information. This version is called when an SQL Server error could occur.
void DumpErrorInfo (IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, BOOL &has_sql_errors ) {
   // Interfaces used in the example.
   IErrorInfo * pIErrorInfoAll = NULL;
   IErrorInfo * pIErrorInfoRecord = NULL;
   IErrorRecords * pIErrorRecords = NULL;
   ISupportErrorInfo * pISupportErrorInfo = NULL;
   ISQLErrorInfo * pISQLErrorInfo = NULL;
   ISQLServerErrorInfo * pISQLServerErrorInfo = NULL;

   // Number of error records.
   ULONG nRecs;
   ULONG nRec;

   // Basic error information from GetBasicErrorInfo.
   ERRORINFO errorinfo;

   // IErrorInfo values.
   BSTR bstrDescription;
   BSTR bstrSource;

   // ISQLErrorInfo parameters.
   BSTR bstrSQLSTATE;
   LONG lNativeError;

   // ISQLServerErrorInfo parameter pointers.
   SSERRORINFO * pSSErrorInfo = NULL;
   OLECHAR * pSSErrorStrings = NULL;

   // Hard-code an American English locale for the example.
   DWORD MYLOCALEID = 0x0409;

   has_sql_errors = 0;

   // Only ask for error information if the interface supports it.
   if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo, (void**) &pISupportErrorInfo)))   
      wprintf(L"SupportErrorErrorInfo interface not supported\n");
   else if (FAILED(pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError)))   
      wprintf(L"InterfaceWithError interface not supported\n");


   // Do not test the return of GetErrorInfo. It can succeed and return
   // a NULL pointer in pIErrorInfoAll. Simply test the pointer.
   GetErrorInfo(0, &pIErrorInfoAll);

   // Test to see if it's a valid OLE DB IErrorInfo interface exposing a list of records.
   if (pIErrorInfoAll != NULL)  {
      if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**) &pIErrorRecords))) {
         pIErrorRecords->GetRecordCount(&nRecs);

         // Within each record, retrieve information from each of the defined interfaces.
         for (nRec = 0; nRec < nRecs; nRec++) {
            ULONG errorno = nRecs - nRec - 1;
            // From IErrorRecords, get the HRESULT and a reference to the ISQLErrorInfo interface.
            pIErrorRecords->GetBasicErrorInfo(errorno, &errorinfo);
            pIErrorRecords->GetCustomErrorObject(errorno,IID_ISQLErrorInfo, (IUnknown**) &pISQLErrorInfo);

            // Display the HRESULT, then use the ISQLErrorInfo.
            wprintf(L"HRESULT:\t%#X\n", errorinfo.hrError);

            if (pISQLErrorInfo != NULL) {
               pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE, &lNativeError);
               // Display SQLSTATE and native error values.
               wprintf(L"SQLSTATE:\t%s\nNative Error:\t%ld\n", bstrSQLSTATE, lNativeError);

               // SysFree BSTR references.
               SysFreeString(bstrSQLSTATE);

               // Get the ISQLServerErrorInfo interface from
               // ISQLErrorInfo before releasing the reference.
               pISQLErrorInfo->QueryInterface(IID_ISQLServerErrorInfo, (void**) &pISQLServerErrorInfo);

               pISQLErrorInfo->Release();
            }

            // Test to ensure the reference is valid, then get error information from ISQLServerErrorInfo.
            if (pISQLServerErrorInfo != NULL) {
               pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo, &pSSErrorStrings);

               // ISQLServerErrorInfo::GetErrorInfo succeeds even when it
               // has nothing to return. Test the pointers before using.
               if (pSSErrorInfo) {
                  // Display the state and severity from the returned
                  // information. The error message comes from
                  // IErrorInfo::GetDescription.
                  wprintf(L"Error state:\t%d\nSeverity:\t%d\n", pSSErrorInfo->bState, pSSErrorInfo->bClass);
                  wprintf(L"Procedure:\t%s\nLine:\t%d\n", pSSErrorInfo->pwszProcedure, pSSErrorInfo->wLineNumber);

                  has_sql_errors++;

                  // IMalloc::Free needed to release references on returned values.
                  pMalloc->Free(pSSErrorStrings);
                  pMalloc->Free(pSSErrorInfo);
               }

               pISQLServerErrorInfo->Release();
            }

            if (SUCCEEDED(pIErrorRecords->GetErrorInfo(errno, MYLOCALEID, &pIErrorInfoRecord))) {
               // Get the source and description (error message) from the record's IErrorInfo.
               pIErrorInfoRecord->GetSource(&bstrSource);
               pIErrorInfoRecord->GetDescription(&bstrDescription);

               if (bstrSource != NULL) {
                  wprintf(L"Source:\t\t%s\n", bstrSource);
                  SysFreeString(bstrSource);
               }

               if (bstrDescription != NULL) {
                  wprintf(L"Error message:\t%s\n", bstrDescription);
                  SysFreeString(bstrDescription);
               }

               pIErrorInfoRecord->Release();
            }
         }

         pIErrorRecords->Release();
      }
      else {
         // IErrorInfo is valid; get the source and
         // description to see what it is.
         pIErrorInfoAll->GetSource(&bstrSource);
         pIErrorInfoAll->GetDescription(&bstrDescription);

         if (bstrSource != NULL) {
            wprintf(L"Source:\t\t%s\n", bstrSource);
            SysFreeString(bstrSource);
         }

         if (bstrDescription != NULL) {
            wprintf(L"Error message:\t%s\n", bstrDescription);
            SysFreeString(bstrDescription);
         }
      }

      pIErrorInfoAll->Release();
   }
   else
      wprintf(L"GetErrorInfo failed.\n");

   if (pISupportErrorInfo != NULL)
      pISupportErrorInfo->Release();
}