Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

401 lines
9.6 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: rpc.cpp
//
// Contents: Cert Server RPC
//
// History: 03-Sep-96 larrys created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <stdio.h>
#include <accctrl.h>
#include "certrpc.h"
#include "certacl.h"
#include "cscom.h"
#include "resource.h"
#define __dwFILE__ __dwFILE_CERTSRV_RPC_CPP__
RPC_BINDING_VECTOR *pvBindings = NULL;
char *pszProtSeqNp = "ncacn_np";
char *pszProtSeqTcp = "ncacn_ip_tcp";
typedef struct _CS_RPC_ATHN_LIST
{
DWORD dwAuthnLevel;
DWORD dwPrinceNameService;
DWORD dwAuthnService;
} CS_RPC_ATHN_LIST ;
CS_RPC_ATHN_LIST g_acsAthnList[] =
{
{ RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_NEGOTIATE },
{ RPC_C_AUTHN_LEVEL_NONE, RPC_C_AUTHN_NONE, RPC_C_AUTHN_NONE }
};
DWORD g_ccsAthnList = sizeof(g_acsAthnList)/sizeof(g_acsAthnList[0]);
HRESULT
RPCInit(VOID)
{
char *pszEndpoint = "\\pipe\\cert";
LPSTR pszPrincName = NULL;
HRESULT hr;
DWORD i;
if (RPC_S_OK == RpcNetworkIsProtseqValidA((unsigned char *) pszProtSeqNp))
{
hr = RpcServerUseProtseqEpA(
(unsigned char *) pszProtSeqNp,
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
(unsigned char *) pszEndpoint,
NULL);
_JumpIfError(hr, error, "RpcServerUseProtseqEpA");
}
if (RPC_S_OK == RpcNetworkIsProtseqValidA((unsigned char *) pszProtSeqTcp))
{
hr = RpcServerUseProtseqA(
(unsigned char *) pszProtSeqTcp,
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
NULL);
if ((HRESULT) ERROR_OUTOFMEMORY == hr)
{
OSVERSIONINFO ovi;
ovi.dwOSVersionInfoSize = sizeof(ovi);
if (GetVersionEx(&ovi) &&
VER_PLATFORM_WIN32_NT == ovi.dwPlatformId &&
4 >= ovi.dwMajorVersion)
{
hr = S_OK; // Ignore IP failure
}
}
_JumpIfError(hr, error, "RpcServerUseProtseqA");
}
hr = RpcServerInqBindings(&pvBindings);
_JumpIfError(hr, error, "RpcServerInqBindings");
hr = RpcServerRegisterIf(s_ICertPassage_v0_0_s_ifspec, NULL, NULL);
_JumpIfError(hr, error, "RpcServerRegisterIf");
// Register Authentication Services
for (i = 0; i < g_ccsAthnList; i++)
{
pszPrincName = NULL;
if (g_acsAthnList[i].dwPrinceNameService != RPC_C_AUTHN_NONE)
{
hr = RpcServerInqDefaultPrincNameA(
g_acsAthnList[i].dwPrinceNameService,
(BYTE **) &pszPrincName);
if (hr != RPC_S_OK)
{
continue;
}
}
hr = RpcServerRegisterAuthInfoA(
(BYTE *) pszPrincName,
g_acsAthnList[i].dwAuthnService,
0,
0);
if(hr == RPC_S_UNKNOWN_AUTHN_SERVICE)
{
continue;
}
if(hr != RPC_S_OK)
{
break;
}
}
if (hr != RPC_S_UNKNOWN_AUTHN_SERVICE)
{
_JumpIfError(hr, error, "RpcServerRegisterAuthInfoA");
}
hr = RpcEpRegister(s_ICertPassage_v0_0_s_ifspec, pvBindings, NULL, NULL);
_JumpIfError(hr, error, "RpcEpRegister");
// Listen, but don't wait...
hr = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
_JumpIfError(hr, error, "RpcServerListen");
error:
if (NULL != pszPrincName)
{
RpcStringFreeA((BYTE **) &pszPrincName);
}
return(hr);
}
HRESULT
RPCTeardown(VOID)
{
HRESULT hr;
// tear down, don't wait for calls to complete
hr = RpcServerUnregisterIf(s_ICertPassage_v0_0_s_ifspec, NULL, FALSE);
_JumpIfError(hr, error, "RpcServerUnregisterIf");
// We have no good way of knowing if all RPC requests are done, so let it
// leak on shutdown.
// RPC_STATUS RPC_ENTRY RpcMgmtWaitServerListen(VOID); ??
hr = S_OK;
error:
return(hr);
}
HRESULT
SetTransBlobString(
CERTTRANSBLOB const *pctb,
WCHAR const **ppwsz)
{
HRESULT hr;
if (NULL != pctb->pb && 0 != pctb->cb)
{
*ppwsz = (WCHAR const *) pctb->pb;
// use lstrlen here for protection against non-zero terminated bufs!
// lstrlen will catch AV's and return error
if ((lstrlen(*ppwsz) + 1) * sizeof(WCHAR) != pctb->cb)
{
hr = E_INVALIDARG;
_JumpIfError(hr, error, "Bad TransBlob string");
}
}
hr = S_OK;
error:
return(hr);
}
/* server prototype */
DWORD
s_CertServerRequest(
/* [in] */ handle_t h,
/* [in] */ DWORD dwFlags,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [ref][out][in] */ DWORD __RPC_FAR *pdwRequestId,
/* [out] */ DWORD __RPC_FAR *pdwDisposition,
/* [ref][in] */ CERTTRANSBLOB const __RPC_FAR *pctbAttribs,
/* [ref][in] */ CERTTRANSBLOB const __RPC_FAR *pctbRequest,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbCertChain,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbEncodedCert,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbDispositionMessage)
{
HRESULT hr = S_OK;
DWORD OpRequest;
WCHAR const *pwszAttributes = NULL;
WCHAR const *pwszSerialNumber = NULL;
CERTTRANSBLOB ctbEmpty = { 0, NULL };
CERTTRANSBLOB const *pctbSerial = &ctbEmpty;
WCHAR *pwszUserName = NULL;
DWORD dwComContextIndex = MAXDWORD;
CERTSRV_COM_CONTEXT ComContext;
CERTSRV_RESULT_CONTEXT ResultContext;
DWORD State = 0;
ZeroMemory(&ComContext, sizeof(ComContext));
ZeroMemory(&ResultContext, sizeof(ResultContext));
DBGPRINT((
DBG_SS_CERTSRV,
"s_CertServerRequest(tid=%d)\n",
GetCurrentThreadId()));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
hr = RegisterComContext(&ComContext, &dwComContextIndex);
_JumpIfError(hr, error, "RegisterComContext");
OpRequest = CR_IN_RETRIEVE;
if (NULL != pctbRequest->pb)
{
*pdwRequestId = 0;
OpRequest = CR_IN_NEW;
}
else
{
// RetrievePending by SerialNumber in pctbAttribs
pctbSerial = pctbAttribs;
pctbAttribs = &ctbEmpty;
}
*pdwDisposition = CR_DISP_ERROR;
__try
{
hr = CheckCertSrvAccess(
pwszAuthority,
h,
CA_ACCESS_ENROLL,
&ComContext.fInRequestGroup,
&ComContext.hAccessToken);
_LeaveIfError(hr, "CheckCertSrvAccess");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
_JumpIfError(hr, error, "CheckCertSrvAccess");
hr = SetTransBlobString(pctbAttribs, &pwszAttributes);
_JumpIfError(hr, error, "SetTransBlobString");
hr = SetTransBlobString(pctbSerial, &pwszSerialNumber);
_JumpIfError(hr, error, "SetTransBlobString");
ResultContext.pdwRequestId = pdwRequestId;
ResultContext.pdwDisposition = pdwDisposition;
ResultContext.pctbDispositionMessage = pctbDispositionMessage;
ResultContext.pctbCert = pctbEncodedCert;
if (CR_IN_FULLRESPONSE & dwFlags)
{
ResultContext.pctbFullResponse = pctbCertChain;
}
else
{
ResultContext.pctbCertChain = pctbCertChain;
}
__try
{
hr = GetClientUserName(
h,
&pwszUserName,
CR_IN_NEW == OpRequest && IsEnterpriseCA(g_CAType)?
&ComContext.pwszUserDN : NULL);
_LeaveIfError(hr, "GetClientUserName");
hr = CoreProcessRequest(
OpRequest | (dwFlags & CR_IN_FORMATMASK),
pwszUserName,
pctbRequest->cb, // cbRequest
pctbRequest->pb, // pbRequest
pwszAttributes,
pwszSerialNumber,
dwComContextIndex,
*pdwRequestId,
&ResultContext); // Allocates returned memory
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
_JumpIfError(hr, error, "CoreProcessRequest");
// Post-processing
pctbDispositionMessage->cb = 0;
if (NULL != pctbDispositionMessage->pb)
{
pctbDispositionMessage->cb =
(wcslen((WCHAR *) pctbDispositionMessage->pb) + 1) * sizeof(WCHAR);
}
error:
ReleaseResult(&ResultContext);
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (NULL != ComContext.hAccessToken)
{
HRESULT hr2;
// closehandle can throw
__try
{
CloseHandle(ComContext.hAccessToken);
}
__except(hr2 = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr2, "Exception");
if (S_OK == hr)
{
hr = hr2;
}
}
}
if (MAXDWORD != dwComContextIndex)
{
if (NULL != ComContext.pwszUserDN)
{
LocalFree(ComContext.pwszUserDN);
}
UnregisterComContext(&ComContext, dwComContextIndex);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
//+--------------------------------------------------------------------------
// MIDL_user_allocate -- Allocates memory for RPC operations.
//
// Parameters:
// cb - # of bytes to allocate
//
// Returns:
// Memory allocated, or NULL if not enough memory.
//---------------------------------------------------------------------------
void __RPC_FAR * __RPC_USER
MIDL_user_allocate(
IN size_t cb)
{
return(CoTaskMemAlloc(cb));
}
//+--------------------------------------------------------------------------
// MIDL_user_free -- Free memory allocated via MIDL_user_allocate.
//
// Parameters:
// pvBuffer - The buffer to free.
//
// Returns:
// None.
//---------------------------------------------------------------------------
void __RPC_USER
MIDL_user_free(
IN void __RPC_FAR *pb)
{
CoTaskMemFree(pb);
}