|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
digesta.cxx
Abstract:
sspi ansi interface for digest package.
Author:
Adriaan Canter (adriaanc) 01-Aug-1998
--*/ #include "include.hxx"
static SecurityFunctionTableA
SecTableA = { SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, EnumerateSecurityPackagesA, NULL, // QueryCredentialsAttributesA
AcquireCredentialsHandleA, FreeCredentialsHandle, NULL, // SspiLogonUserA
InitializeSecurityContextA, AcceptSecurityContext, CompleteAuthToken, DeleteSecurityContext, ApplyControlToken, QueryContextAttributesA, ImpersonateSecurityContext, RevertSecurityContext, MakeSignature, VerifySignature, FreeContextBuffer, QuerySecurityPackageInfoA, NULL, // Reserved3
NULL, // Reserved4
NULL, // ExportSecurityContext
NULL, // ImportSecurityContextA
NULL, // Reserved7
NULL, // Reserved8
NULL, // QuerySecurityContextToken
NULL, // EncryptMessage
NULL // DecryptMessage
};
//--------------------------------------------------------------------------
//
// Function: InitSecurityInterfaceA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" PSecurityFunctionTableA SEC_ENTRY InitSecurityInterfaceA(VOID) { PSecurityFunctionTableA pSecTableA = &SecTableA; return pSecTableA; }
//--------------------------------------------------------------------------
//
// Function: AcquireCredentialsHandleA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
// HEINOUS SSPI HACK here: AcquireCredentialsHandle is called with the package
// name ("Digest") as the package identifier. When AcquireCredentialsHandle returns
// to the caller PCredHandle->dwLower is set by security.dll to be the index of
// the package returned. EnumerateSecurityPackages. This is how SSPI resolves the
// correct provider dll when subsequent calls are made through the dispatch table
// (PSecurityFunctionTale). Any credential *or* context handle handed out by the
// package must have the dwLower member set to this index so that subsequent calls
// can resolve the dll from the handle.
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleA( LPSTR pszPrincipal, // Name of principal
LPSTR pszPackageName, // Name of package
DWORD dwCredentialUse, // Flags indicating use
VOID SEC_FAR * pvLogonId, // Pointer to logon ID
VOID SEC_FAR * pAuthData, // Package specific data
SEC_GET_KEY_FN pGetKeyFn, // Pointer to GetKey() func
VOID SEC_FAR * pvGetKeyArgument, // Value to pass to GetKey()
PCredHandle phCredential, // (out) Cred Handle
PTimeStamp ptsExpiry // (out) Lifetime (optional)
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
SECURITY_STATUS ssResult;
// Outbound credentials only.
if (!(dwCredentialUse & SECPKG_CRED_OUTBOUND) || (dwCredentialUse & SECPKG_CRED_INBOUND)) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_UNKNOWN_CREDENTIALS; goto exit; }
// Logon to cache.
// Logon to the cache and get the session context.
CSess *pSess; PSEC_WINNT_AUTH_IDENTITY_EXA pSecIdExA; PSEC_WINNT_AUTH_IDENTITY pSecId;
// HTTP clients will pass in this structure.
pSecIdExA = (PSEC_WINNT_AUTH_IDENTITY_EXA) pAuthData;
// Non-HTTP clients (OE4, OE5) will pass in this structure.
pSecId = (PSEC_WINNT_AUTH_IDENTITY) pAuthData;
// Check for HTTP client application logon.
if (pAuthData && (pSecIdExA->Version == sizeof(SEC_WINNT_AUTH_IDENTITY_EXA)) && pSecIdExA->User && pSecIdExA->UserLength == sizeof(DIGEST_PKG_DATA)) { DIGEST_PKG_DATA *pPkgData; pPkgData = (DIGEST_PKG_DATA*) pSecIdExA->User; pSess = g_pCache->LogOnToCache(pPkgData->szAppCtx, pPkgData->szUserCtx, TRUE); } // Check for non-HTTP client application logon.
else { // Find or create the single non-HTTP session.
pSess = g_pCache->LogOnToCache(NULL, NULL, FALSE);
// If user+pass+realm (domain) is passed in, create and
// attach a matching credential to this session.
if (pAuthData && pSecId->User && pSecId->UserLength && pSecId->Domain && pSecId->DomainLength && pSecId->Password && pSecId->PasswordLength) { // Create a credential with the information passed in.
CCred *pCred; CCredInfo *pInfo; pInfo = new CCredInfo(NULL, (LPSTR) pSecId->Domain, (LPSTR) pSecId->User, (LPSTR) pSecId->Password, NULL, NULL); if (pInfo) { pCred = g_pCache->CreateCred(pSess, pInfo); delete pInfo; } } }
// BUGBUG - return better error codes.
if (!pSess) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_INTERNAL_ERROR; goto exit; }
// Hand out the session handle.
phCredential->dwUpper = g_pCache->MapSessionToHandle(pSess);
// ***** phCredential->dwLower will be set by security.dll *****
ssResult = SEC_E_OK;
exit: return ssResult; }
//--------------------------------------------------------------------------
//
// Function: FreeCredentialsHandle
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY FreeCredentialsHandle(PCredHandle phCredential) { // bugbug - asserted.
if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
SECURITY_STATUS ssResult;
// Get the session context from the handle.
CSess *pSess;
pSess = g_pCache->MapHandleToSession(phCredential->dwUpper); if (!pSess) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_UNKNOWN_CREDENTIALS; goto exit; }
// Logoff from the cache.
if (g_pCache->LogOffFromCache(pSess) != ERROR_SUCCESS) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_INTERNAL_ERROR; goto exit; } ssResult = SEC_E_OK; exit: return ssResult; }
//--------------------------------------------------------------------------
//
// Function: InitializeSecurityContextA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA( PCredHandle phCredential, // Cred to base context
PCtxtHandle phContext, // Existing context (OPT)
LPSTR pszTargetName, // Name of target
DWORD fContextReq, // Context Requirements
DWORD Reserved1, // Reserved, MBZ
DWORD TargetDataRep, // Data rep of target
PSecBufferDesc pInput, // Input Buffers
DWORD Reserved2, // Reserved, MBZ
PCtxtHandle phNewContext, // (out) New Context handle
PSecBufferDesc pOutput, // (inout) Output Buffers
DWORD SEC_FAR * pfContextAttr, // (out) Context attrs
PTimeStamp ptsExpiry // (out) Life span (OPT)
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
LPSTR szHost, szRealm, szUser, szPass, szNonce; DWORD cbHost, cbRealm, cbUser, cbPass, cbNonce;
LPSTR szCtx = NULL; SECURITY_STATUS ssResult = SEC_E_OK;
// Client nonce NULL except for md5-sess.
LPSTR szCNonce = NULL;
CSess *pSess; CCred *pCred; CParams *pParams = NULL; CCredInfo *pInfo = NULL;
// Rude credential flush for all apps.
if (!phCredential && (fContextReq & ISC_REQ_NULL_SESSION)) { g_pCache->FlushCreds(NULL, NULL); ssResult = SEC_E_OK; goto exit; }
// Get the session pointer from the handle.
pSess = g_pCache->MapHandleToSession(phCredential->dwUpper); if (!pSess) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_UNKNOWN_CREDENTIALS; goto exit; }
// Legacy conn. oriented client may require a continue
// message on null buffer input.
if (!pSess->fHTTP && !pInput && pOutput) { *((LPDWORD) (pOutput->pBuffers[0].pvBuffer)) = 0; pOutput->pBuffers[0].cbBuffer = sizeof(DWORD); ssResult = SEC_I_CONTINUE_NEEDED; goto exit; }
// Flush creds for indicated session.
if (fContextReq & ISC_REQ_NULL_SESSION) { g_pCache->FlushCreds(pSess, NULL); ssResult = SEC_E_OK; goto exit; }
DIGEST_ASSERT(phCredential && pInput && pOutput);
// Parse the challenge to a params object.
if (CDigest::ParseChallenge(pSess, pInput, &pParams, fContextReq) != ERROR_SUCCESS) { // DIGEST_ASSERT(FALSE);
ssResult = SEC_E_INVALID_TOKEN; goto exit; }
// Get host, realm (required) and any nonce, user & pass.
pParams->GetParam(CParams::HOST, &szHost, &cbHost); pParams->GetParam(CParams::REALM, &szRealm, &cbRealm); pParams->GetParam(CParams::NONCE, &szNonce, &cbNonce); pParams->GetParam(CParams::USER, &szUser, &cbUser); pParams->GetParam(CParams::PASS, &szPass, &cbPass);
// If prompting UI is indicated.
if (fContextReq & ISC_REQ_PROMPT_FOR_CREDS) { CCredInfo *pInfoIn, *pInfoOut;
// Attempt to get one or more cred infos
pInfoIn = g_pCache->FindCred(pSess, szHost, szRealm, szUser, NULL, NULL, FIND_CRED_UI);
// Get the persistence key from pSess
szCtx = CSess::GetCtx(pSess); DIGEST_ASSERT(szCtx);
// If this is prompting for UI specifying md5-sess,
// create a client nonce to associate with cred.
if (pParams->IsMd5Sess()) szCNonce = CDigest::MakeCNonce();
pParams->GetParam(CParams::HOST, &szHost, &cbHost);
// Prompt with authentication dialog.
if (DigestErrorDlg(szCtx, szHost, szRealm, szUser, szNonce, szCNonce, pInfoIn, &pInfoOut, pParams->GetHwnd()) == ERROR_SUCCESS) { DIGEST_ASSERT(pInfoOut);
// Create the credential.
pCred = g_pCache->CreateCred(pSess, pInfoOut);
// Record that the host is trusted.
if (pSess->fHTTP) CCredCache::SetTrustedHostInfo(szCtx, pParams);
} else { ssResult = SEC_E_NO_CREDENTIALS; goto exit; }
// Retrieve the credentials just created.
pInfo = g_pCache->FindCred(pSess, szHost, szRealm, pInfoOut->szUser, szNonce, szCNonce, FIND_CRED_AUTH);
// Clean up one or more cred infos.
// BUGBUG - null out pointers after freeing.
while (pInfoIn) { CCredInfo *pNext; pNext = pInfoIn->pNext; delete pInfoIn; pInfoIn = pNext; }
if (pInfoOut) delete pInfoOut;
if (szCNonce) delete szCNonce;
if (!pInfo) { ssResult = SEC_E_NO_CREDENTIALS; goto exit; }
}
// Otherwise we are attempting to authenticate. We may be either
// authenticating in response to a challenge or pre-authenticating.
else { // Get the persistence key from pSess
szCtx = CSess::GetCtx(pSess); DIGEST_ASSERT(szCtx);
// For HTTP sessions we check the trusted host list unless
// 1) credentials are supplied, or 2) a context has been passed
// in which specifically instructs to ignore the host list.
if (pSess->fHTTP && !pParams->IsPreAuth() && !pParams->AreCredsSupplied()) { if (!phContext || !(phContext->dwUpper & DIGEST_PKG_FLAGS_IGNORE_TRUSTED_HOST_LIST)) { if (!CCredCache::IsTrustedHost(szCtx, szHost)) { ssResult = SEC_E_NO_CREDENTIALS; goto exit; } } }
// If preauthenticating.
if (pParams->IsPreAuth()) { // If using supplied credentials.
if (pParams->AreCredsSupplied()) { // Create a cred info using supplied values. Include passed-in NC.
pInfo = new CCredInfo(szHost, szRealm, szUser, szPass, szNonce, szCNonce); pInfo->cCount = pParams->GetNC();
if (!(pInfo && pInfo->dwStatus == ERROR_SUCCESS)) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_INTERNAL_ERROR; goto exit; } } // Otherwise attempt to find cred info in cache.
else { // Attempt to find the credentials from realm and any user.
pInfo = g_pCache->FindCred(pSess, szHost, szRealm, szUser, NULL, NULL, FIND_CRED_PREAUTH); }
// Return if no credentials exist.
if (!pInfo) { ssResult = SEC_E_NO_CREDENTIALS; goto exit; } } // Otherwise auth in response to challenge.
else { // Check if logoff is requested.
CHAR* szLogoff; szLogoff = pParams->GetParam(CParams::LOGOFF); if (szLogoff && !lstrcmpi(szLogoff, "TRUE")) { g_pCache->FlushCreds(NULL, szRealm); ssResult = SEC_E_CONTEXT_EXPIRED; goto exit; }
// If a context is passed in examine the stale header unless specifically
// directed not to.
if (pSess->fHTTP && phContext && !pParams->AreCredsSupplied() && !(phContext->dwUpper & DIGEST_PKG_FLAGS_IGNORE_STALE_HEADER)) { CHAR* szStale; DWORD cbStale; pParams->GetParam(CParams::STALE, &szStale, &cbStale); if (!szStale || !lstrcmpi(szStale, "FALSE")) { ssResult = SEC_E_NO_CREDENTIALS; goto exit; } }
// If this is authenticating specifying md5-sess,
// create a client nonce to associate with cred.
if (pParams->IsMd5Sess()) szCNonce = CDigest::MakeCNonce();
// If credentials are supplied, create an entry in
// the credential cache. We search as usual subsequently.
if (pParams->AreCredsSupplied()) { // Create a cred info using supplied values.
pInfo = new CCredInfo(szHost, szRealm, szUser, szPass, szNonce, szCNonce);
if (!(pInfo && pInfo->dwStatus == ERROR_SUCCESS)) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_INTERNAL_ERROR; goto exit; }
pCred = g_pCache->CreateCred(pSess, pInfo); delete pInfo; }
// Attempt to find the credentials from realm and any user.
pInfo = g_pCache->FindCred(pSess, szHost, szRealm, szUser, szNonce, szCNonce, FIND_CRED_AUTH);
// Return if no credentials exist.
if (!pInfo) { ssResult = SEC_E_NO_CREDENTIALS; goto exit; } } }
// We should now have the appropriate cred info. Generate the response.
DIGEST_ASSERT(pInfo); if (CDigest::GenerateResponse(pSess, pParams, pInfo, pOutput) != ERROR_SUCCESS) { DIGEST_ASSERT(FALSE); ssResult = SEC_E_INTERNAL_ERROR; goto exit; }
// Delete cred info if allocated.
// bugbug - move further down.
if (pInfo) delete pInfo;
ssResult = SEC_E_OK;
exit:
if ((ssResult != SEC_E_OK) && (ssResult != SEC_I_CONTINUE_NEEDED)) pOutput->pBuffers[0].cbBuffer = 0;
// BUGBUG - delete pInfo if not NULL.
// Delete persistence key if allocated.
if (szCtx) delete szCtx;
// Identify the new context.
if (phNewContext && phCredential) phNewContext->dwLower = phCredential->dwLower;
// Delete the params object.
if (pParams) delete pParams;
return ssResult; }
//--------------------------------------------------------------------------
//
// Function: AcceptSecurityContext
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY AcceptSecurityContext( PCredHandle phCredential, // Cred to base context
PCtxtHandle phContext, // Existing context (OPT)
PSecBufferDesc pInput, // Input buffer
unsigned long fContextReq, // Context Requirements
unsigned long TargetDataRep, // Target Data Rep
PCtxtHandle phNewContext, // (out) New context handle
PSecBufferDesc pOutput, // (inout) Output buffers
unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes
PTimeStamp ptsExpiry // (out) Life span (OPT)
) { // BUGBUG - don't need initglobals.
if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return(SEC_E_UNSUPPORTED_FUNCTION); }
//--------------------------------------------------------------------------
//
// Function: DeleteSecurityContext
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY DeleteSecurityContext( PCtxtHandle phContext // Context to delete
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: ApplyControlToken
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY ApplyControlToken( PCtxtHandle phContext, // Context to modify
PSecBufferDesc pInput // Input token to apply
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
SECURITY_STATUS ssResult;
// Current flags used are
// DIGEST_PKG_FLAG_IGNORE_TRUSTED_HOST_LIST
// DIGEST_PKG_FLAG_IGNORE_STALE_HEADER
phContext->dwUpper |= *((LPDWORD) (pInput->pBuffers[0].pvBuffer));
ssResult = SEC_E_OK; return ssResult; }
//--------------------------------------------------------------------------
//
// Function: EnumerateSecurityPackagesA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(DWORD SEC_FAR *pcPackages, PSecPkgInfoA SEC_FAR *ppSecPkgInfo) {
SECURITY_STATUS ssResult; // BUGBUG - ALLOW ASSERTS?
ssResult = QuerySecurityPackageInfoA(PACKAGE_NAME, ppSecPkgInfo); if (ssResult == SEC_E_OK) { *pcPackages = 1; } return ssResult; }
//--------------------------------------------------------------------------
//
// Function: QuerySecurityPackageInfoA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoA(LPSTR szPackageName, PSecPkgInfoA SEC_FAR *ppSecPkgInfo) { // BUGBUG - ALLOW ASSERTS?
PSecPkgInfoA pSecPkgInfo; DWORD cbSecPkgInfo; SECURITY_STATUS ssResult; LPSTR pCur;
if (strcmp(szPackageName, PACKAGE_NAME)) { ssResult = SEC_E_SECPKG_NOT_FOUND; goto exit; }
cbSecPkgInfo = sizeof(SecPkgInfoA) + sizeof(PACKAGE_NAME) + sizeof(PACKAGE_COMMENT);
pSecPkgInfo = (PSecPkgInfoA) LocalAlloc(0,cbSecPkgInfo);
if (!pSecPkgInfo) { ssResult = SEC_E_INSUFFICIENT_MEMORY; goto exit; }
pSecPkgInfo->fCapabilities = PACKAGE_CAPABILITIES; pSecPkgInfo->wVersion = PACKAGE_VERSION; pSecPkgInfo->wRPCID = PACKAGE_RPCID; pSecPkgInfo->cbMaxToken = PACKAGE_MAXTOKEN;
pCur = (LPSTR) (pSecPkgInfo) + sizeof(SecPkgInfoA);
pSecPkgInfo->Name = pCur; memcpy(pSecPkgInfo->Name, PACKAGE_NAME, sizeof(PACKAGE_NAME)); pCur += sizeof(PACKAGE_NAME);
pSecPkgInfo->Comment = pCur; memcpy(pSecPkgInfo->Comment, PACKAGE_COMMENT, sizeof(PACKAGE_COMMENT));
*ppSecPkgInfo = pSecPkgInfo;
ssResult = SEC_E_OK;
exit: return ssResult; }
//--------------------------------------------------------------------------
//
// Function: FreeContextBuffer
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY FreeContextBuffer(void SEC_FAR *pvContextBuffer) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
LocalFree(pvContextBuffer); return SEC_E_OK; }
//--------------------------------------------------------------------------
//
// Function: CompleteAuthToken
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY CompleteAuthToken( PCtxtHandle phContext, // Context to complete
PSecBufferDesc pToken // Token to complete
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: ImpersonateSecurityContext
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY ImpersonateSecurityContext( PCtxtHandle phContext // Context to impersonate
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: RevertSecurityContext
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY RevertSecurityContext( PCtxtHandle phContext // Context from which to re
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: QueryContextAttributesA
//
// Synopsis:
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY QueryContextAttributesA( PCtxtHandle phContext, // Context to query
unsigned long ulAttribute, // Attribute to query
void SEC_FAR * pBuffer // Buffer for attributes
) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: MakeSignature
//
// Synopsis:
//
// Effects:
//
// Arguments: [phContext] -- context to use
// [fQOP] -- quality of protection to use
// [pMessage] -- message
// [MessageSeqNo] -- sequence number of message
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY MakeSignature( PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
//--------------------------------------------------------------------------
//
// Function: VerifySignature
//
// Synopsis:
//
// Effects:
//
// Arguments: [phContext] -- Context performing the unseal
// [pMessage] -- Message to verify
// [MessageSeqNo] -- Sequence number of this message
// [pfQOPUsed] -- quality of protection used
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
extern "C" SECURITY_STATUS SEC_ENTRY VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG * pfQOP) { if (!InitGlobals()) return SEC_E_INTERNAL_ERROR;
return SEC_E_UNSUPPORTED_FUNCTION; }
|