394 lines
13 KiB
C
394 lines
13 KiB
C
/*#----------------------------------------------------------------------------
|
|
**
|
|
** File: sspcalls.c
|
|
**
|
|
** Synopsis: This module contains SSPI function calls for SSPI SPM DLL.
|
|
**
|
|
** Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
**
|
|
** Authors: LucyC Created 25 Sept. 1995
|
|
**
|
|
**---------------------------------------------------------------------------*/
|
|
|
|
#include "msnspmh.h"
|
|
#include <debugmem.h>
|
|
#include "urlmon.h"
|
|
|
|
BOOL g_fUUEncodeData = TRUE;
|
|
|
|
typedef enum _COMPUTER_NAME_FORMAT {
|
|
ComputerNameNetBIOS,
|
|
ComputerNameDnsHostname,
|
|
ComputerNameDnsDomain,
|
|
ComputerNameDnsFullyQualified,
|
|
ComputerNamePhysicalNetBIOS,
|
|
ComputerNamePhysicalDnsHostname,
|
|
ComputerNamePhysicalDnsDomain,
|
|
ComputerNamePhysicalDnsFullyQualified,
|
|
ComputerNameMax
|
|
} COMPUTER_NAME_FORMAT ;
|
|
|
|
typedef
|
|
BOOL
|
|
(WINAPI * PFN_GET_COMPUTER_NAME_EX)(
|
|
IN COMPUTER_NAME_FORMAT NameType,
|
|
OUT LPSTR lpBuffer,
|
|
IN OUT LPDWORD nSize
|
|
);
|
|
|
|
PFN_GET_COMPUTER_NAME_EX g_pfnGetComputerNameExA = NULL;
|
|
|
|
DWORD GetZoneFromUrl(LPSTR pszUrl);
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
**
|
|
** Function: GetSecAuthMsg
|
|
**
|
|
** Synopsis: This function generates a SSPI NEGOTIATE or RESPONSE
|
|
** authorization string for the specified SSPI package.
|
|
** The authorization string generated by this function
|
|
** follows the format:
|
|
** "<Package Name> <Package Specific Auth. Data>"
|
|
** If global uuencoding is turned on, this functions will
|
|
** uuencode the message before building it into an
|
|
** authorization string; by default, the uuencoding flag is
|
|
** always on.
|
|
** This functions calls InitializeSecurityContext() to
|
|
** generate the NEGOTIATE/RESPONSE message for the authori-
|
|
** zation string. If the SSPI function returns NO_CREDENTIAL,
|
|
** and if the PROMPT_CREDS flag is not turned on when blocking
|
|
** is permitted, this function will call the SSPI function
|
|
** again with the PROMPT_CREDS flag set; if SSPI returns
|
|
** NO_CREDENTIAL again, this SSPI will return ERROR to the
|
|
** caller.
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** pData - pointer to SspData containing the SSPI function table
|
|
** and the SSPI package list.
|
|
** pkgID - the package index of the SSPI package to use.
|
|
** pInContext - pointer to a context handle. If NULL is specified,
|
|
** this function will use a temporary space for the context
|
|
** handle and delete the handle before returning to the
|
|
** caller. If non-NULL address is specified, the context
|
|
** handle created by the SSPI is returned to the caller.
|
|
** And the caller will have to delete the handle when it's
|
|
** done with it.
|
|
** fContextReq - the SSPI request flag to pass to InitializeSecurityContext
|
|
** pBuffIn - pointer to the uudecoded CHALLENGE message if any.
|
|
** For generating NEGOTIATE message, this pointer should be NULL.
|
|
** cbBuffIn - length of the CHALLENGE message. This should be zero when
|
|
** when pBuffIn is NULL.
|
|
** pFinalBuff - pointer to a buffer for the final authorization string.
|
|
** pszTarget - Server Host Name
|
|
** bNonBlock - a flag which is set if blocking is not permitted.
|
|
**
|
|
** Return Value:
|
|
**
|
|
** SPM_STATUS_OK - if an authorization string is generated successfully
|
|
** SPM_STATUS_WOULD_BLOCK - if generating an authorization string would
|
|
** cause blocking when blocking is not permitted.
|
|
** SPM_ERROR - if any problem/error is encountered in generating an
|
|
** authorization string, including user hitting cancel on
|
|
** the SSPI dialog prompt for name/password.
|
|
**
|
|
**---------------------------------------------------------------------------*/
|
|
DWORD
|
|
GetSecAuthMsg (
|
|
PSspData pData,
|
|
PCredHandle pCredential,
|
|
DWORD pkgID, // the package index into package list
|
|
PCtxtHandle pInContext,
|
|
PCtxtHandle pOutContext,
|
|
ULONG fContextReq, // Request Flags
|
|
VOID *pBuffIn,
|
|
DWORD cbBuffIn,
|
|
char *pFinalBuff,
|
|
DWORD *pcbBuffOut,
|
|
SEC_CHAR *pszTarget, // Server Host Name
|
|
UINT bNonBlock,
|
|
LPSTR pszScheme,
|
|
PCSTR lpszUrl,
|
|
SECURITY_STATUS *pssResult
|
|
)
|
|
{
|
|
// char szDecodedBuf[MAX_BLOB_SIZE];
|
|
// char *szDecodedBuf;
|
|
// char FastDecodedBuf[MAX_BLOB_SIZE];
|
|
char *SlowDecodedBuf = NULL;
|
|
|
|
int retsize;
|
|
SECURITY_STATUS SecStat;
|
|
TimeStamp Lifetime;
|
|
SecBufferDesc OutBuffDesc;
|
|
SecBuffer OutSecBuff;
|
|
SecBufferDesc InBuffDesc;
|
|
SecBuffer InSecBuff;
|
|
ULONG ContextAttributes;
|
|
|
|
// char OutBufPlain[MAX_AUTH_MSG_SIZE];
|
|
char *SlowOutBufPlain = NULL;
|
|
|
|
char *pOutMsg = NULL;
|
|
DWORD RetStatus;
|
|
long maxbufsize;
|
|
CHAR szDecoratedTarget[MAX_PATH + 6];
|
|
DWORD cbTarget;
|
|
|
|
ULONG cbMaxToken;
|
|
|
|
|
|
//
|
|
// BUGBUG: Deal with output buffer not being long enough
|
|
|
|
|
|
if (pFinalBuff == NULL) {
|
|
return(SPM_ERROR);
|
|
}
|
|
|
|
//
|
|
// Prepare our output buffer. We use a temporary buffer because
|
|
// the real output buffer will most likely need to be uuencoded
|
|
//
|
|
OutBuffDesc.ulVersion = 0;
|
|
OutBuffDesc.cBuffers = 1;
|
|
OutBuffDesc.pBuffers = &OutSecBuff;
|
|
|
|
OutSecBuff.cbBuffer = MAX_AUTH_MSG_SIZE;
|
|
OutSecBuff.BufferType = SECBUFFER_TOKEN;
|
|
|
|
|
|
// Always use the slow alloc'ed buf as a quick fix to appease
|
|
// DAV redir stress scenarios, which run in svchost and starts
|
|
// with a 4KB stack limit.
|
|
cbMaxToken = GetPkgMaxToken( pkgID );
|
|
|
|
SlowOutBufPlain = (char *) ALLOCATE_FIXED_MEMORY(cbMaxToken);
|
|
|
|
if( SlowOutBufPlain == NULL )
|
|
{
|
|
RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
OutSecBuff.pvBuffer = SlowOutBufPlain;
|
|
OutSecBuff.cbBuffer = cbMaxToken;
|
|
|
|
//
|
|
// Prepare our Input buffer if a CHALLENGE message is passed in.
|
|
//
|
|
if ( pBuffIn )
|
|
{
|
|
InBuffDesc.ulVersion = 0;
|
|
InBuffDesc.cBuffers = 1;
|
|
InBuffDesc.pBuffers = &InSecBuff;
|
|
|
|
InSecBuff.BufferType = SECBUFFER_TOKEN;
|
|
|
|
//
|
|
// If this is UUENCODED, decode it first
|
|
//
|
|
if ( g_fUUEncodeData)
|
|
{
|
|
DWORD cbDecodedBuf;
|
|
|
|
cbDecodedBuf = cbBuffIn;
|
|
SlowDecodedBuf = ALLOCATE_FIXED_MEMORY(cbDecodedBuf);
|
|
if( SlowDecodedBuf == NULL )
|
|
{
|
|
RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
InSecBuff.cbBuffer = HTUU_decode (pBuffIn, SlowDecodedBuf,
|
|
cbDecodedBuf);
|
|
InSecBuff.pvBuffer = SlowDecodedBuf;
|
|
}
|
|
else
|
|
{
|
|
InSecBuff.cbBuffer = cbBuffIn;
|
|
InSecBuff.pvBuffer = pBuffIn;
|
|
}
|
|
}
|
|
|
|
// If scheme is Negotiate, set ISC_REQ_MUTUAL_AUTH and decorate
|
|
// the server name indicated by pszTarget by appending a '$' to the
|
|
// server name.
|
|
if (pszScheme && !(lstrcmpi(pszScheme, "Negotiate")))
|
|
{
|
|
fContextReq |= ISC_REQ_MUTUAL_AUTH;
|
|
cbTarget = (pszTarget ? strlen(pszTarget) : 0);
|
|
if (cbTarget && (cbTarget <= MAX_PATH - sizeof( "HTTP/" )))
|
|
{
|
|
memcpy(szDecoratedTarget, "HTTP/", sizeof( "HTTP/" ) - 1 );
|
|
memcpy(szDecoratedTarget + sizeof( "HTTP/" ) - 1, pszTarget, cbTarget + 1);
|
|
pszTarget = szDecoratedTarget;
|
|
|
|
// OutputDebugStringA(pszTarget);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call SSPI function generate the NEGOTIATE/RESPONSE message
|
|
//
|
|
|
|
if (fContextReq & ISC_REQ_DELEGATE)
|
|
{
|
|
// we should only request delegation when calling InitializeSecurityContext if
|
|
// the site is in the intranet or trusted sites zone. Otherwise you will be giving
|
|
// the user's TGT to any web server that is trusted for delegation.
|
|
|
|
DWORD dwZone = GetZoneFromUrl((PSTR)lpszUrl);
|
|
|
|
if ((dwZone != URLZONE_INTRANET) && (dwZone != URLZONE_TRUSTED))
|
|
{
|
|
fContextReq &= ~ISC_REQ_DELEGATE;
|
|
}
|
|
}
|
|
|
|
SspiRetry:
|
|
|
|
//
|
|
// BUGBUG: Same credential handle could be used by multiple threads at the
|
|
// same time.
|
|
//
|
|
SecStat = (*(pData->pFuncTbl->InitializeSecurityContext))(
|
|
pCredential,
|
|
pInContext,
|
|
pszTarget,
|
|
fContextReq,
|
|
0,
|
|
SECURITY_NATIVE_DREP,
|
|
(pBuffIn) ? &InBuffDesc : NULL,
|
|
0,
|
|
pOutContext,
|
|
&OutBuffDesc,
|
|
&ContextAttributes,
|
|
&Lifetime );
|
|
*pssResult = SecStat;
|
|
|
|
//
|
|
// If SSPI function fails
|
|
//
|
|
if ( !NT_SUCCESS( SecStat ) )
|
|
{
|
|
RetStatus = SPM_ERROR;
|
|
|
|
//
|
|
// If SSPI do not have user name/password for the secified package,
|
|
//
|
|
if ((SecStat == SEC_E_NO_CREDENTIALS) ||
|
|
(g_fIsWhistler && (SecStat == SEC_E_LOGON_DENIED)))
|
|
{
|
|
//
|
|
// If we have prompted the user and still get back "No Credential"
|
|
// error, it means the user does not have valid credential; the
|
|
// user hit <CANCEL> on the UI box. If we have supplied a valid
|
|
// credential, but get back a "No Credential" error, then something
|
|
// has gone wrong; we definitely should return to caller with ERROR
|
|
//
|
|
if ((fContextReq & ISC_REQ_PROMPT_FOR_CREDS) ||
|
|
(fContextReq & ISC_REQ_USE_SUPPLIED_CREDS))
|
|
{
|
|
RetStatus = SPM_ERROR; // return ERROR to caller
|
|
}
|
|
else if (bNonBlock)
|
|
{
|
|
//
|
|
// Blocking is not permitted, return WOULD_BLOCK to caller
|
|
//
|
|
RetStatus = SPM_STATUS_WOULD_BLOCK;
|
|
}
|
|
else
|
|
{
|
|
// Blocking is permitted and we have not asked the SSPI to
|
|
// prompt the user for proper credential, we should call
|
|
// the SSPI again with PROMPT_CREDS flag set.
|
|
//
|
|
fContextReq = fContextReq | ISC_REQ_PROMPT_FOR_CREDS;
|
|
goto SspiRetry;
|
|
}
|
|
}
|
|
SetLastError( SecStat );
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
RetStatus = SPM_STATUS_OK;
|
|
|
|
#if 0
|
|
//
|
|
// note: when support for processing final MUTUAL_AUTH blob is added,
|
|
// will need to allow for non-existent output buffer.
|
|
//
|
|
|
|
if( OutSecBuff.cbBuffer == 0 )
|
|
{
|
|
*pcbBuffOut = 0;
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Only return the SSPI blob if a output buffer is specified
|
|
//
|
|
if (pFinalBuff)
|
|
{
|
|
//
|
|
// Initialize the final buffer to hold the package name followed by
|
|
// a space. And setup the pOutMsg pointer to points to the character
|
|
// following the space so that the final NEGOTIATE/RESPONSE can be
|
|
// copied into the pFinalBuff starting at the character pointed to
|
|
// by pOutMsg.
|
|
//
|
|
wsprintf (pFinalBuff, "%s ", pData->PkgList[pkgID]->pName);
|
|
pOutMsg = pFinalBuff + lstrlen(pFinalBuff);
|
|
|
|
if ( g_fUUEncodeData)
|
|
{
|
|
maxbufsize = *pcbBuffOut -
|
|
lstrlen(pData->PkgList[pkgID]->pName) - 1;
|
|
//
|
|
// uuencode it, but make sure that it fits in the given buffer
|
|
//
|
|
retsize = HTUU_encode ((BYTE *) OutSecBuff.pvBuffer,
|
|
OutSecBuff.cbBuffer,
|
|
(CHAR *) pOutMsg, maxbufsize);
|
|
if (retsize > 0)
|
|
*pcbBuffOut = retsize + lstrlen(pData->PkgList[pkgID]->pName)+1;
|
|
else
|
|
RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if ( *pcbBuffOut >= lstrlen(pData->PkgList[pkgID]->pName) +
|
|
OutSecBuff.cbBuffer + 1 )
|
|
{
|
|
CopyMemory( (CHAR *) pOutMsg,
|
|
OutSecBuff.pvBuffer,
|
|
OutSecBuff.cbBuffer );
|
|
*pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) + 1 +
|
|
OutSecBuff.cbBuffer;
|
|
}
|
|
else
|
|
{
|
|
*pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) +
|
|
OutSecBuff.cbBuffer + 1;
|
|
RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( SlowOutBufPlain != NULL )
|
|
{
|
|
FREE_MEMORY( SlowOutBufPlain );
|
|
}
|
|
|
|
if( SlowDecodedBuf != NULL )
|
|
{
|
|
FREE_MEMORY( SlowDecodedBuf );
|
|
}
|
|
|
|
return (RetStatus);
|
|
}
|
|
|