/**********************************************************************/ /** 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; }