windows-nt/Source/XPSP1/NT/ds/security/services/ca/certclib/ctnotify.cpp
2020-09-26 16:20:57 +08:00

336 lines
9.1 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000
//
// File: ctnotify.cpp
//
// Contents: Cert Type Change Notification APIS
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <winldap.h>
#include <ntldap.h>
#include <cainfop.h>
#include <ctnotify.h>
#include <certca.h>
#include "csldap.h"
static WCHAR * s_wszLocation = L"CN=Certificate Templates,CN=Public Key Services,CN=Services,";
//-----------------------------------------------------------------------
//
// CertTypeQueryProc
//
// The thread to recieve change notification from DS
//
//-----------------------------------------------------------------------
DWORD WINAPI CertTypeQueryProc(LPVOID lpParameter)
{
CERTTYPE_QUERY_INFO *pCertTypeQueryInfo=NULL;
ULONG ldaperr=0;
LDAPMessage *results = NULL;
if(NULL==lpParameter)
return FALSE;
pCertTypeQueryInfo = (CERTTYPE_QUERY_INFO *)lpParameter;
//we wait for the notifications
while(TRUE)
{
ldaperr = ldap_result(
pCertTypeQueryInfo->pldap,
pCertTypeQueryInfo->msgID, // message identifier
LDAP_MSG_ONE, // retrieve one message at a time
NULL, // no timeout
&results); // receives the search results
if ((ldaperr == (ULONG) -1) || ((results) == NULL))
{
//the result failed
break;
}
//some change has happened.
(pCertTypeQueryInfo->dwChangeSequence)++;
//make sure that we will never return 0
if(0 == (pCertTypeQueryInfo->dwChangeSequence))
{
(pCertTypeQueryInfo->dwChangeSequence)++;
}
ldap_msgfree(results);
results=NULL;
}
return TRUE;
}
//---------------------------------------------------------------------------
//
// CACertTypeRegisterQuery
//
//---------------------------------------------------------------------------
HRESULT
CACertTypeRegisterQuery(
IN DWORD dwFlag,
IN LPVOID pvldap,
OUT HCERTTYPEQUERY *phCertTypeQuery)
{
HRESULT hr=E_INVALIDARG;
LDAPControl simpleControl;
PLDAPControl controlArray[2];
LPWSTR rgwszAttribs[2];
ULONG ldaperr=0;
DWORD dwThreadID=0;
LDAP *pldap=NULL;
CERTSTR bstrConfig = NULL;
CERTSTR bstrCertTemplatesContainer = NULL;
//memory is freed via the thread proc
CERTTYPE_QUERY_INFO *pCertTypeQueryInfo=NULL;
//assign the input parameter
pldap = (LDAP *)pvldap;
if(NULL==phCertTypeQuery)
_JumpError(hr, error, "NULL param");
pCertTypeQueryInfo=(CERTTYPE_QUERY_INFO *)LocalAlloc(LPTR, sizeof(CERTTYPE_QUERY_INFO));
if(NULL==pCertTypeQueryInfo)
{
hr=E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
memset(pCertTypeQueryInfo, 0, sizeof(CERTTYPE_QUERY_INFO));
//we start the change sequence as 1
pCertTypeQueryInfo->dwChangeSequence = 1;
//bind to DS
if(pldap)
{
pCertTypeQueryInfo->pldap=pldap;
}
else
{
//retrieve the ldap handle
if(S_OK != (hr = myDoesDSExist(TRUE)))
_JumpError(hr , error, "myDoesDSExist");
hr = myRobustLdapBindEx(
FALSE, // fGC
FALSE, // fRediscover
LDAP_VERSION3, // uVersion
NULL, // pwszDomainName
&pCertTypeQueryInfo->pldap,
NULL); // ppwszForestDNSName
_JumpIfError(hr , error, "myRobustLdapBindEx");
pCertTypeQueryInfo->fUnbind=TRUE;
}
//retrieve the config string
hr = CAGetAuthoritativeDomainDn(pCertTypeQueryInfo->pldap, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
//build the template container DN
bstrCertTemplatesContainer = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszLocation));
if(bstrCertTemplatesContainer == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CertAllocStringLen");
}
wcscpy(bstrCertTemplatesContainer, s_wszLocation);
wcscat(bstrCertTemplatesContainer, bstrConfig);
// Set up the change notification control.
simpleControl.ldctl_oid = LDAP_SERVER_NOTIFICATION_OID_W;
simpleControl.ldctl_iscritical = TRUE;
simpleControl.ldctl_value.bv_len = 0;
simpleControl.ldctl_value.bv_val = NULL;
controlArray[0] = &simpleControl;
controlArray[1] = NULL;
rgwszAttribs[0] = L"cn";
rgwszAttribs[1] = NULL;
// Start a persistent asynchronous search.
ldaperr = ldap_search_ext(
pCertTypeQueryInfo->pldap,
(PWCHAR) bstrCertTemplatesContainer, // Template container DN
LDAP_SCOPE_ONELEVEL,
L"ObjectClass=*",
rgwszAttribs, // Attributes to retrieve
1, // Retrieve attributes only
(PLDAPControl *) &controlArray, // Server size controls
NULL, // Client controls
0, // Timeout
0, // Sizelimit
(PULONG)&(pCertTypeQueryInfo->msgID) // Receives identifier for results
);
if (LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pCertTypeQueryInfo->pldap, ldaperr, NULL);
_JumpError(hr, error, "ldap_search_ext");
}
//start a thread to wait for the notification
pCertTypeQueryInfo->hThread = CreateThread(
NULL,
0,
CertTypeQueryProc,
pCertTypeQueryInfo,
0, //execute immediately
&dwThreadID);
if(NULL == pCertTypeQueryInfo->hThread)
{
hr=myHError(GetLastError());
_JumpError(hr, error, "CreateThread");
}
*phCertTypeQuery=pCertTypeQueryInfo;
pCertTypeQueryInfo=NULL;
hr=S_OK;
error:
if(bstrConfig)
CertFreeString(bstrConfig);
if(bstrCertTemplatesContainer)
{
CertFreeString(bstrCertTemplatesContainer);
}
if(pCertTypeQueryInfo)
{
if(pCertTypeQueryInfo->fUnbind)
{
if(pCertTypeQueryInfo->pldap)
ldap_unbind(pCertTypeQueryInfo->pldap);
}
if(pCertTypeQueryInfo->hThread)
CloseHandle(pCertTypeQueryInfo->hThread);
LocalFree(pCertTypeQueryInfo);
pCertTypeQueryInfo=NULL;
}
return hr;
}
//---------------------------------------------------------------------------
//
// CACertTypeQuery
//
//---------------------------------------------------------------------------
HRESULT
CACertTypeQuery(
IN HCERTTYPEQUERY hCertTypeQuery,
OUT DWORD *pdwChangeSequence)
{
CERTTYPE_QUERY_INFO *pCertTypeQueryInfo=NULL;
if((NULL==pdwChangeSequence) || (NULL==hCertTypeQuery))
return E_INVALIDARG;
pCertTypeQueryInfo = (CERTTYPE_QUERY_INFO *)hCertTypeQuery;
*pdwChangeSequence = pCertTypeQueryInfo->dwChangeSequence;
return S_OK;
}
//---------------------------------------------------------------------------
//
// CACertTypeUnregisterQuery
//
//---------------------------------------------------------------------------
HRESULT
CACertTypeUnregisterQuery(
IN HCERTTYPEQUERY hCertTypeQuery)
{
CERTTYPE_QUERY_INFO *pCertTypeQueryInfo=NULL;
ULONG ldaperr=0;
HRESULT hr=E_INVALIDARG;
DWORD dwWait=0;
if(NULL==hCertTypeQuery)
_JumpError(hr, error, "NULL param");
pCertTypeQueryInfo = (CERTTYPE_QUERY_INFO *)hCertTypeQuery;
if(NULL == (pCertTypeQueryInfo->pldap))
_JumpError(hr, error, "NULL pldap");
//abandom the in-progress asynchronous ldap_result call
ldaperr=ldap_abandon(pCertTypeQueryInfo->pldap, pCertTypeQueryInfo->msgID);
if(LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pCertTypeQueryInfo->pldap, ldaperr, NULL);
_JumpError(hr, error, "ldap_abandon");
}
//wait for the thread to finish
dwWait = WaitForSingleObject(pCertTypeQueryInfo->hThread, INFINITE);
if(WAIT_OBJECT_0 != dwWait)
{
hr = myHError(GetLastError());
_JumpError(hr, error, "WaitForSingleObject");
}
hr=S_OK;
error:
//free the memory
if(pCertTypeQueryInfo)
{
if(pCertTypeQueryInfo->fUnbind)
{
if(pCertTypeQueryInfo->pldap)
ldap_unbind(pCertTypeQueryInfo->pldap);
}
if(pCertTypeQueryInfo->hThread)
CloseHandle(pCertTypeQueryInfo->hThread);
LocalFree(pCertTypeQueryInfo);
pCertTypeQueryInfo=NULL;
}
return hr;
}