mirror of https://github.com/lianthony/NT4.0
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.
381 lines
8.5 KiB
381 lines
8.5 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1993 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
security.c
|
|
|
|
This module manages security for the W3 Service.
|
|
|
|
|
|
FILE HISTORY:
|
|
KeithMo 07-Mar-1993 Created.
|
|
|
|
*/
|
|
|
|
|
|
#include "w3p.hxx"
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
//
|
|
// Private functions
|
|
//
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
BOOL
|
|
HTTP_REQ_BASE::SendAuthNeededResp(
|
|
BOOL * pfFinished
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends an access denied HTTP server response with the accompanying
|
|
authentication schemes the server supports
|
|
|
|
Parameters:
|
|
|
|
pfFinished - If set to TRUE, indicates no further processing is needed
|
|
for this request
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE on error
|
|
|
|
--*/
|
|
{
|
|
CHAR * pszTail;
|
|
DWORD cbRespBufUsed;
|
|
DWORD cbRespBufLeft;
|
|
DWORD cbNeeded;
|
|
|
|
*pfFinished = FALSE;
|
|
|
|
if ( !HTTP_REQ_BASE::BuildStatusLine( QueryRespBuf(),
|
|
!IsProxyRequest() ? HT_DENIED :
|
|
HT_PROXY_AUTH_REQ,
|
|
NO_ERROR ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make sure there's enough size for any ISAPI denial headers plus any
|
|
// admin specified access denied message
|
|
//
|
|
|
|
cbRespBufUsed = QueryRespBufCB();
|
|
cbRespBufLeft = QueryRespBuf()->QuerySize() - cbRespBufUsed;
|
|
|
|
cbNeeded = strlen( g_pszAccessDeniedMsg ) +
|
|
_strDenialHdrs.QueryCB() +
|
|
250; // Other misc headers
|
|
|
|
if ( cbNeeded > cbRespBufLeft )
|
|
{
|
|
if ( !QueryRespBuf()->Resize( cbNeeded + cbRespBufUsed ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pszTail = QueryRespBufPtr() + cbRespBufUsed;
|
|
|
|
//
|
|
// If this is not the first call, then return the current authentication
|
|
// data blob otherwise return the forms of authentication the server
|
|
// accepts
|
|
//
|
|
|
|
if ( IsAuthenticating() )
|
|
{
|
|
pszTail += wsprintf( pszTail,
|
|
"%s: %s\r\n",
|
|
(IsProxyRequest() ? "Proxy-Authenticate" :
|
|
"WWW-Authenticate"),
|
|
_strAuthInfo.QueryStr() );
|
|
}
|
|
else
|
|
{
|
|
if ( !AppendAuthenticationHdrs( QueryRespBuf(),
|
|
&pszTail,
|
|
pfFinished ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( *pfFinished )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if ( IsKeepConnSet() )
|
|
{
|
|
if ( !IsProxyRequest() )
|
|
{
|
|
strcat( pszTail,
|
|
"Connection: keep-alive\r\n");
|
|
pszTail += sizeof( "Connection: keep-alive\r\n" ) - sizeof(CHAR);
|
|
}
|
|
else
|
|
{
|
|
strcat( pszTail,
|
|
"Proxy-Connection: keep-alive\r\n");
|
|
pszTail += sizeof( "Proxy-Connection: keep-alive\r\n" ) - sizeof(CHAR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add any additional headers supplied by the filters plus the header
|
|
// termination
|
|
//
|
|
|
|
pszTail += wsprintf( pszTail,
|
|
"Content-Length: %d\r\n"
|
|
"Content-Type: text/html\r\n"
|
|
"%s\r\n"
|
|
"%s",
|
|
strlen( g_pszAccessDeniedMsg ),
|
|
_strDenialHdrs.QueryStr(),
|
|
g_pszAccessDeniedMsg );
|
|
|
|
TCP_ASSERT( QueryRespBuf()->QuerySize() > QueryRespBufCB() );
|
|
|
|
IF_DEBUG( PARSING )
|
|
{
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
"[SendAuthNeededResp] Sending headers: %s",
|
|
QueryRespBufPtr() ));
|
|
}
|
|
|
|
return WriteFile( QueryRespBufPtr(),
|
|
QueryRespBufCB(),
|
|
NULL,
|
|
IO_FLAG_ASYNC );
|
|
}
|
|
|
|
|
|
BOOL
|
|
HTTP_REQ_BASE::AppendAuthenticationHdrs(
|
|
BUFFER * pRespBuf,
|
|
CHAR * * ppszTail,
|
|
BOOL * pfFinished
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method adds the appropriate "WWW-Authenticate" strings to the passed
|
|
server response string
|
|
|
|
This routine assumes pRespBuf is large enough to hold the authentication
|
|
headers
|
|
|
|
Parameters:
|
|
|
|
pRespBuf - Buffer of response headers
|
|
ppszTail - End of buffer to append data on to
|
|
pfFinished - Set to TRUE if no further processing is needed on this request
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE on error
|
|
|
|
--*/
|
|
{
|
|
CHAR * pchField;
|
|
CHAR * pszResp;
|
|
CHAR * pszTail;
|
|
CHAR * pszRealm = g_pszRealm;
|
|
|
|
//
|
|
// If no realm was supplied in the registry, use the host name
|
|
//
|
|
|
|
if ( !pszRealm )
|
|
{
|
|
pszRealm = QueryHostAddr();
|
|
}
|
|
|
|
//
|
|
// Notify any Access Denied filters the user has been denied access
|
|
//
|
|
|
|
if ( fAnyFilters )
|
|
{
|
|
if ( !_Filter.NotifyAccessDenied( &_Filter,
|
|
_strURL.QueryStr(),
|
|
_strPhysicalPath.QueryStr(),
|
|
pfFinished ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( *pfFinished )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
pszTail = *ppszTail;
|
|
|
|
//
|
|
// Send the correct header depending on if we're a proxy
|
|
//
|
|
|
|
if ( !IsProxyRequest() )
|
|
pchField = "WWW-Authenticate: ";
|
|
else
|
|
pchField = "Proxy-Authenticate: ";
|
|
|
|
if ( g_pTsvcInfo->QueryAuthentication() & INET_INFO_AUTH_NT_AUTH )
|
|
{
|
|
DWORD i = 0;
|
|
|
|
//
|
|
// For each authentication package the server supports, add a
|
|
// WWW-Authenticate header
|
|
//
|
|
|
|
while ( apszNTProviders[i] )
|
|
{
|
|
pszTail += wsprintf( pszTail,
|
|
"%s%s\r\n",
|
|
pchField,
|
|
apszNTProviders[i++] );
|
|
}
|
|
}
|
|
|
|
if ( g_pTsvcInfo->QueryAuthentication() & INET_INFO_AUTH_CLEARTEXT )
|
|
{
|
|
pszTail += wsprintf( pszTail,
|
|
"%sBasic realm=\"%s\"\r\n",
|
|
pchField,
|
|
pszRealm );
|
|
}
|
|
|
|
TCP_ASSERT( (pszTail - (CHAR *)pRespBuf->QueryPtr() ) <
|
|
(LONG) pRespBuf->QuerySize() );
|
|
|
|
*ppszTail = pszTail;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
HTTP_REQ_BASE::ExtractClearNameAndPswd(
|
|
CHAR * pch,
|
|
STR * pstrUserName,
|
|
STR * pstrPassword,
|
|
BOOL fUUEncoded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method breaks a string in the form "username:password" and
|
|
places the components into pstrUserName and pstrPassword. If fUUEncoded
|
|
is TRUE, then the string is UUDecoded first.
|
|
|
|
Parameters:
|
|
|
|
pch - Pointer to <username>:<password>
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE on error
|
|
|
|
--*/
|
|
{
|
|
STR strDecoded;
|
|
CHAR * pchtmp;
|
|
|
|
pch = SkipWhite( pch );
|
|
|
|
if ( fUUEncoded )
|
|
{
|
|
if ( !uudecode( pch,
|
|
&strDecoded ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pch = strDecoded.QueryStrA();
|
|
}
|
|
|
|
pchtmp = SkipTo( pch, TEXT(':') );
|
|
|
|
if ( *pchtmp == TEXT(':') )
|
|
{
|
|
*pchtmp = TEXT('\0');
|
|
|
|
if ( !_strUserName.Copy( pch ) ||
|
|
!_strPassword.Copy( pchtmp + 1 ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HANDLE
|
|
HTTP_REQ_BASE::QueryPrimaryToken(
|
|
HANDLE * phDelete
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method returns a non-impersonation user token handle that's
|
|
usable with CreateProcessAsUser.
|
|
|
|
Parameters:
|
|
|
|
phDelete - If returned as non-null, the caller is responsible for calling
|
|
CloseHandle on this value when done using the returned value.
|
|
|
|
Return Value:
|
|
|
|
The primary token handle if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
*phDelete = NULL;
|
|
|
|
if ( !QueryVrootImpersonateHandle() )
|
|
{
|
|
return _tcpauth.QueryPrimaryToken();
|
|
}
|
|
|
|
//
|
|
// This is an impersonation token so dupe it to a primary token
|
|
//
|
|
|
|
if ( !DuplicateTokenEx( QueryVrootImpersonateHandle(),
|
|
TOKEN_ALL_ACCESS,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
phDelete ))
|
|
{
|
|
TCP_PRINT(( DBG_CONTEXT,
|
|
"[QueryPrimaryToken] DuplicateToken failed, error %lx\n",
|
|
GetLastError() ));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return *phDelete;
|
|
}
|