windows-nt/Source/XPSP1/NT/ds/security/services/ca/certadm/backup.cpp

957 lines
22 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: backup.cpp
//
// Contents: Cert Server client database backup APIs
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "certsrvd.h"
#include "csdisp.h"
#include "certadmp.h"
#define __dwFILE__ __dwFILE_CERTADM_BACKUP_CPP__
#if DBG
#define _CERTBCLI_TYPECHECK
#endif
#include <certbcli.h>
WCHAR g_wszBackupAnnotation[] = L"backup";
WCHAR g_wszRestoreAnnotation[] = L"restore";
HRESULT
AllocateContext(
IN WCHAR const *pwszConfig,
OUT CSBACKUPCONTEXT **ppcsbc)
{
HRESULT hr;
WCHAR *pwszT = NULL;
CSASSERT(NULL != pfnCertSrvIsServerOnline);
pwszT = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszConfig) + 1) * sizeof(WCHAR));
if (NULL == pwszT)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszT, pwszConfig);
*ppcsbc = (CSBACKUPCONTEXT *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(**ppcsbc));
if (NULL == *ppcsbc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
(*ppcsbc)->pwszConfig = pwszT;
pwszT = NULL;
hr = S_OK;
error:
if (NULL != pwszT)
{
LocalFree(pwszT);
}
return(hr);
}
VOID
ReleaseContext(
IN OUT CSBACKUPCONTEXT *pcsbc)
{
CSASSERT(NULL != pcsbc);
if (NULL != pcsbc->pwszConfig)
{
LocalFree(const_cast<WCHAR *>(pcsbc->pwszConfig));
pcsbc->pwszConfig = NULL;
}
if (NULL != pcsbc->pICertAdminD)
{
CloseAdminServer(&pcsbc->pICertAdminD);
CSASSERT(NULL == pcsbc->pICertAdminD);
}
if (NULL != pcsbc->pbReadBuffer)
{
VirtualFree(pcsbc->pbReadBuffer, 0, MEM_RELEASE);
}
LocalFree(pcsbc);
}
HRESULT
OpenAdminServer(
IN WCHAR const *pwszConfig,
OUT WCHAR const **ppwszAuthority,
OUT DWORD *pdwServerVersion,
OUT ICertAdminD2 **ppICertAdminD)
{
HRESULT hr;
BOOL fCoInitialized = FALSE;
hr = CoInitialize(NULL);
if (RPC_E_CHANGED_MODE == hr)
{
_PrintError(hr, "CoInitialize");
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
}
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInitialized = TRUE;
*pdwServerVersion = 0;
hr = myOpenAdminDComConnection(
pwszConfig,
ppwszAuthority,
NULL,
pdwServerVersion,
ppICertAdminD);
_JumpIfError(hr, error, "myOpenDComConnection");
CSASSERT(0 != *pdwServerVersion);
error:
if (S_OK != hr && fCoInitialized)
{
CoUninitialize();
}
return(hr);
}
VOID
CloseAdminServer(
IN OUT ICertAdminD2 **ppICertAdminD)
{
myCloseDComConnection((IUnknown **) ppICertAdminD, NULL);
CoUninitialize();
}
//+--------------------------------------------------------------------------
// CertSrvIsServerOnline -- check to see if the Cert Server is Online on the
// given server. This call is guaranteed to return quickly.
//
// Parameters:
// [in] pwszConfig - name of the server to check
// [out] pfServerOnline - pointer to receive the bool result
// (TRUE if Cert Server is online; FALSE, otherwise)
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//+--------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvIsServerOnlineW(
IN WCHAR const *pwszConfig,
OPTIONAL OUT BOOL *pfServerOnline)
{
HRESULT hr;
ICertAdminD2 *pICertAdminD = NULL;
WCHAR const *pwszAuthority;
DWORD State;
DWORD dwServerVersion;
if (NULL == pwszConfig)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
__try
{
if (NULL != pfServerOnline)
{
*pfServerOnline = FALSE;
}
hr = OpenAdminServer(
pwszConfig,
&pwszAuthority,
&dwServerVersion,
&pICertAdminD);
// OpenAdminServer etc might get E_ACCESSDENIED -- meaning server down
if (S_OK != hr)
{
_PrintError(hr, "OpenAdminServer");
if (E_ACCESSDENIED == hr || (HRESULT) ERROR_ACCESS_DENIED == hr)
{
hr = S_OK;
}
__leave;
}
hr = pICertAdminD->GetServerState(pwszAuthority, &State);
_LeaveIfError(hr, "GetServerState");
if (NULL != pfServerOnline && 0 != State)
{
*pfServerOnline = TRUE;
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if (NULL != pICertAdminD)
{
CloseAdminServer(&pICertAdminD);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupPrepare -- prepare the DS for the online backup and return a
// Backup Context Handle to be used for subsequent calls to backup
// functions.
//
// Parameters:
// [in] pwszConfig - server name to prepare for online backup
// [in] grbitJet - flag to be passed to jet while backing up dbs
// [in] dwBackupFlags - CSBACKUP_TYPE_FULL or CSBACKUP_TYPE_LOGS_ONLY
// [out] phbc - pointer that will receive the backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupPrepareW(
IN WCHAR const *pwszConfig,
IN ULONG grbitJet,
IN ULONG dwBackupFlags,
OUT HCSBC *phbc)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc = NULL;
if (NULL == pwszConfig || NULL == phbc)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*phbc = NULL;
if (CSBACKUP_TYPE_LOGS_ONLY == dwBackupFlags)
{
grbitJet |= JET_bitBackupIncremental;
}
else if (CSBACKUP_TYPE_FULL != dwBackupFlags)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "dwBackupFlags");
}
__try
{
hr = AllocateContext(pwszConfig, &pcsbc);
_LeaveIfError(hr, "AllocateContext");
hr = OpenAdminServer(
pcsbc->pwszConfig,
&pcsbc->pwszAuthority,
&pcsbc->dwServerVersion,
&pcsbc->pICertAdminD);
_LeaveIfError(hr, "OpenAdminServer");
hr = pcsbc->pICertAdminD->BackupPrepare(
pcsbc->pwszAuthority,
grbitJet,
dwBackupFlags,
g_wszBackupAnnotation,
0); // dwClientIdentifier
_LeaveIfError(hr, "BackupPrepare");
*phbc = (HCSBC) pcsbc;
pcsbc = NULL;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if (NULL != pcsbc)
{
ReleaseContext(pcsbc);
}
return(hr);
}
// Return the length of a double '\0' terminated string -- includes the
// trailing '\0's.
DWORD
mySzzLen(
CHAR const *pszz)
{
CHAR const *psz;
DWORD cb;
psz = pszz;
do
{
cb = strlen(psz);
psz += cb + 1;
} while (0 != cb);
return SAFE_SUBTRACT_POINTERS(psz, pszz); // includes double trailing '\0's
}
HRESULT
myLocalAllocCopy(
IN VOID *pbIn,
IN DWORD cbIn,
OUT VOID **pbOut)
{
HRESULT hr;
*pbOut = LocalAlloc(LMEM_FIXED, cbIn);
if (NULL == *pbOut)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(*pbOut, pbIn, cbIn);
hr = S_OK;
error:
return(hr);
}
HRESULT
BackupRestoreGetFileList(
IN DWORD FileListType,
IN HCSBC hbc,
OUT WCHAR **ppwszzFileList,
OUT DWORD *pcbList)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
WCHAR *pwszzFileList = NULL;
LONG cwcList;
DWORD cbList;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
if (NULL != ppwszzFileList)
{
*ppwszzFileList = NULL;
}
if (NULL != pcbList)
{
*pcbList = 0;
}
if (NULL == ppwszzFileList || NULL == pcbList)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
pcsbc = (CSBACKUPCONTEXT *) hbc;
__try
{
if (NULL == pcsbc->pICertAdminD)
{
hr = OpenAdminServer(
pcsbc->pwszConfig,
&pcsbc->pwszAuthority,
&pcsbc->dwServerVersion,
&pcsbc->pICertAdminD);
_LeaveIfError(hr, "OpenAdminServer");
}
CSASSERT(NULL != pcsbc->pICertAdminD);
if (FLT_DBFILES == FileListType)
{
hr = pcsbc->pICertAdminD->BackupGetAttachmentInformation(
&pwszzFileList,
&cwcList);
_LeaveIfError(hr, "BackupGetAttachmentInformation");
}
else if (FLT_LOGFILES == FileListType)
{
hr = pcsbc->pICertAdminD->BackupGetBackupLogs(
&pwszzFileList,
&cwcList);
_LeaveIfError(hr, "BackupGetBackupLogs");
}
else if (FLT_DYNAMICFILES == FileListType)
{
hr = pcsbc->pICertAdminD->BackupGetDynamicFiles(
&pwszzFileList,
&cwcList);
_LeaveIfError(hr, "BackupGetDynamicFileList");
}
else
{
CSASSERT(FLT_RESTOREDBLOCATIONS == FileListType);
hr = pcsbc->pICertAdminD->RestoreGetDatabaseLocations(
&pwszzFileList,
&cwcList);
_LeaveIfError(hr, "RestoreGetDatabaseLocations");
}
cbList = cwcList * sizeof(WCHAR);
myRegisterMemAlloc(pwszzFileList, cbList, CSM_COTASKALLOC);
hr = myLocalAllocCopy(pwszzFileList, cbList, (VOID **) ppwszzFileList);
_JumpIfError(hr, error, "myLocalAllocCopy");
*pcbList = cbList;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if (NULL != pwszzFileList)
{
CoTaskMemFree(pwszzFileList);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupGetDatabaseNames -- return the list of data bases that need to
// be backed up for the given backup context The information returned in
// ppwszzFileList should not be interpreted, as it only has meaning on
// the server being backed up.
//
// This API will allocate a buffer of sufficient size to hold the entire
// attachment list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] ppwszzFileList - pointer that will receive the pointer to the
// attachment info; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; ppwszzFileList info is an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupGetDatabaseNamesW(
IN HCSBC hbc,
OUT WCHAR **ppwszzFileList,
OUT DWORD *pcbList)
{
HRESULT hr;
hr = BackupRestoreGetFileList(FLT_DBFILES, hbc, ppwszzFileList, pcbList);
_JumpIfError(hr, error, "BackupRestoreGetFileList");
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupGetDynamicFileList -- return the list of dynamic files that
// need to be backed up for the given backup context The information
// returned in ppwszzFileList should not be interpreted, as it only has
// meaning on the server being backed up.
//
// This API will allocate a buffer of sufficient size to hold the entire
// attachment list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] ppwszzFileList - pointer that will receive the pointer to the
// attachment info; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; ppwszzFileList info is an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupGetDynamicFileListW(
IN HCSBC hbc,
OUT WCHAR **ppwszzFileList,
OUT DWORD *pcbList)
{
HRESULT hr;
hr = BackupRestoreGetFileList(
FLT_DYNAMICFILES,
hbc,
ppwszzFileList,
pcbList);
_JumpIfError(hr, error, "BackupRestoreGetFileList");
error:
return(hr);
}
#define CBREADMIN (64 * 1024) // 64k minimum buffer
#define CBREADDEFAULT (512 * 1024) // 512k recommended
#define CBREADMAX (4 * 1024 * 1024) // 4mb maximum buffer
HRESULT
BufferAllocate(
IN DWORD cbHintSize,
OUT BYTE **ppbBuffer,
OUT DWORD *pcbBuffer)
{
HRESULT hr;
DWORD cb;
*ppbBuffer = NULL;
if (0 == cbHintSize)
{
// at 512k the server begins doing efficient backups
cbHintSize = CBREADDEFAULT;
}
else if (CBREADMIN > cbHintSize)
{
cbHintSize = CBREADMIN;
}
for (cb = CBREADMAX; (cb >> 1) >= cbHintSize; cb >>= 1)
;
while (TRUE)
{
*ppbBuffer = (BYTE *) VirtualAlloc(
NULL,
cb,
MEM_COMMIT,
PAGE_READWRITE);
if (NULL != *ppbBuffer)
{
break;
}
hr = myHLastError();
CSASSERT(S_OK == hr);
_PrintError(hr, "VirtualAlloc");
cb >>= 1;
if (CBREADMIN > cb)
{
goto error;
}
}
*pcbBuffer = cb;
hr = S_OK;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupOpenFile -- open a remote file for backup, and perform whatever
// client and server side operations to prepare for the backup.
// It takes in a hint of the size of the buffer that will later be passed
// into the CertSrvBackupRead API that can be used to optimize the network
// traffic for the API.
//
// Parameters:
// [in] hbc - backup context handle
// [in] pwszPath - name of the attachment to be opened for read
// [in] cbReadHintSize - suggested size in bytes that might be used
// during the subsequent reads on this attachment
// [out] pliFileSize - pointer to a large integer that would receive the
// size in bytes of the given attachment
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupOpenFileW(
IN HCSBC hbc,
IN WCHAR const *pwszPath,
IN DWORD cbReadHintSize,
OUT LARGE_INTEGER *pliFileSize)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
if (NULL == pwszPath || NULL == pliFileSize)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
pcsbc = (CSBACKUPCONTEXT *) hbc;
if (pcsbc->fFileOpen)
{
hr = HRESULT_FROM_WIN32(ERROR_BUSY);
_JumpError(hr, error, "File already open");
}
__try
{
hr = pcsbc->pICertAdminD->BackupOpenFile(
pwszPath,
(ULONGLONG *) pliFileSize);
_LeaveIfErrorStr(hr, "BackupOpenFile", pwszPath);
if (NULL == pcsbc->pbReadBuffer)
{
hr = BufferAllocate(
cbReadHintSize,
&pcsbc->pbReadBuffer,
&pcsbc->cbReadBuffer);
_LeaveIfError(hr, "BufferAllocate");
}
pcsbc->fFileOpen = TRUE;
pcsbc->cbCache = 0;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupRead -- read the currently open attachment bytes into the given
// buffer. The client application is expected to call this function
// repeatedly until it gets the entire file (the application would have
// received the file size through the CertSrvBackupOpenFile call before.
//
// Parameters:
// [in] hbc - backup context handle
// [in] pvBuffer - pointer to the buffer that would receive the read data.
// [in] cbBuffer - specifies the size of the above buffer
// [out] pcbRead - pointer to receive the actual number of bytes read.
//
// Returns:
// HRESULT - The status of the operation.
// S_OK if successful.
// ERROR_END_OF_FILE if the end of file was reached while being backed up
// Other Win32 and RPC error code.
//
// Note:
// It is important to realize that pcbRead may be less than cbBuffer.
// This does not indicate an error, some transports may choose to fragment
// the buffer being transmitted instead of returning the entire buffers
// worth of data.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupRead(
IN HCSBC hbc,
IN VOID *pvBuffer,
IN DWORD cbBuffer,
OUT DWORD *pcbRead)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
BYTE *pbBuffer = (BYTE *) pvBuffer;
DWORD cbRead;
DWORD cb;
hr = E_HANDLE;
if (NULL == hbc)
{
_JumpError(hr, error, "NULL handle");
}
if (NULL == pvBuffer || NULL == pcbRead)
{
hr = E_POINTER;
_JumpError(hr, error, "NULL parm");
}
*pcbRead = 0;
pcsbc = (CSBACKUPCONTEXT *) hbc;
if (NULL == pcsbc->pbReadBuffer)
{
_JumpError(hr, error, "NULL buffer");
}
if (!pcsbc->fFileOpen)
{
_JumpError(hr, error, "File not open");
}
while (TRUE)
{
if (0 != pcsbc->cbCache)
{
cb = min(pcsbc->cbCache, cbBuffer);
CopyMemory(pbBuffer, pcsbc->pbCache, cb);
pbBuffer += cb;
cbBuffer -= cb;
pcsbc->pbCache += cb;
pcsbc->cbCache -= cb;
*pcbRead += cb;
}
if (0 == cbBuffer)
{
hr = S_OK;
break; // request satisfied
}
pcsbc->cbCache = 0;
__try
{
hr = pcsbc->pICertAdminD->BackupReadFile(
pcsbc->pbReadBuffer,
pcsbc->cbReadBuffer,
(LONG *) &cbRead);
_LeaveIfError(hr, "BackupReadFile");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
if (S_OK != hr || 0 == cbRead)
{
break; // EOF
}
pcsbc->cbCache = cbRead;
pcsbc->pbCache = pcsbc->pbReadBuffer;
}
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupClose -- called by the application after it completes reading
// all the data in the currently opened attachement.
//
// Parameters:
// [in] hbc - backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupClose(
IN HCSBC hbc)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
hr = E_HANDLE;
if (NULL == hbc)
{
_JumpError(hr, error, "NULL handle");
}
pcsbc = (CSBACKUPCONTEXT *) hbc;
if (!pcsbc->fFileOpen)
{
_JumpError(hr, error, "File not open");
}
__try
{
hr = pcsbc->pICertAdminD->BackupCloseFile();
_LeaveIfError(hr, "BackupCloseFile");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
// Clear flag even on failure...
pcsbc->fFileOpen = FALSE;
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupGetBackupLogs -- return the list of log files that need to be
// backed up for the given backup context
//
// This API will allocate a buffer of sufficient size to hold the entire
// backup log list, which must be later freed with CertSrvBackupFree.
//
// Parameters:
// [in] hbc - backup context handle
// [out] pszBackupLogFiles - pointer that will receive the pointer to the
// list of log files; allocated memory should be freed using
// CertSrvBackupFree() API by the caller when it is no longer
// needed; Log files are returned in an array of null-terminated
// filenames and the list is terminated by two L'\0's.
// [out] pcbList - will receive the number of bytes returned
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupGetBackupLogsW(
IN HCSBC hbc,
OUT WCHAR **ppwszzFileList,
OUT DWORD *pcbList)
{
HRESULT hr;
hr = BackupRestoreGetFileList(
FLT_LOGFILES,
hbc,
ppwszzFileList,
pcbList);
_JumpIfError(hr, error, "BackupRestoreGetFileList");
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupTruncateLogs -- terminate the backup operation. Called when
// the backup has completed successfully.
//
// Parameters:
// [in] hbc - backup context handle
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//
// Note:
// Again, this API may have to take a grbit parameter to be passed to the
// server to indicate the backup type.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupTruncateLogs(
IN HCSBC hbc)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
pcsbc = (CSBACKUPCONTEXT *) hbc;
__try
{
hr = pcsbc->pICertAdminD->BackupTruncateLogs();
_LeaveIfError(hr, "BackupTruncateLogs");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupEnd -- clean up after a backup operation has been performed.
// This API will close outstanding binding handles, and do whatever is
// necessary to clean up after successful/unsuccesful backup attempts.
//
// Parameters:
// [in] hbc - backup context handle of the backup session
//
// Returns:
// S_OK if the call executed successfully;
// Failure code otherwise.
//---------------------------------------------------------------------------
HRESULT
CERTBCLI_API
CertSrvBackupEnd(
IN HCSBC hbc)
{
HRESULT hr;
CSBACKUPCONTEXT *pcsbc;
if (NULL == hbc)
{
hr = E_HANDLE;
_JumpError(hr, error, "NULL handle");
}
pcsbc = (CSBACKUPCONTEXT *) hbc;
__try
{
hr = pcsbc->pICertAdminD->BackupEnd();
_LeaveIfError(hr, "BackupEnd");
ReleaseContext((CSBACKUPCONTEXT *) hbc);
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
return(hr);
}
//+--------------------------------------------------------------------------
// CertSrvBackupFree -- free any buffer allocated by certbcli.dll APIs.
//
// Parameters:
// [in] pv - pointer to the buffer that is to be freed.
//
// Returns:
// None.
//---------------------------------------------------------------------------
VOID
CERTBCLI_API
CertSrvBackupFree(
IN VOID *pv)
{
LocalFree(pv);
}