//+--------------------------------------------------------------------------- // // Microsoft Windows NT Security // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: inetsp.cpp // // Contents: Inet Scheme Provider for Remote Object Retrieval // // History: 06-Aug-97 kirtd Created // //---------------------------------------------------------------------------- #include //+--------------------------------------------------------------------------- // // Function: InetRetrieveEncodedObject // // Synopsis: retrieve encoded object via HTTP, FTP, GOPHER protocols // //---------------------------------------------------------------------------- BOOL WINAPI InetRetrieveEncodedObject ( IN LPCSTR pszUrl, IN LPCSTR pszObjectOid, IN DWORD dwRetrievalFlags, IN DWORD dwTimeout, OUT PCRYPT_BLOB_ARRAY pObject, OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject, OUT LPVOID* ppvFreeContext, IN HCRYPTASYNC hAsyncRetrieve, IN PCRYPT_CREDENTIALS pCredentials, IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { BOOL fResult; IObjectRetriever* por = NULL; if ( !( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) ) { por = new CInetSynchronousRetriever; } if ( por == NULL ) { SetLastError( (DWORD) E_OUTOFMEMORY ); return( FALSE ); } fResult = por->RetrieveObjectByUrl( pszUrl, pszObjectOid, dwRetrievalFlags, dwTimeout, (LPVOID *)pObject, ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, NULL, pAuxInfo ); por->Release(); return( fResult ); } //+--------------------------------------------------------------------------- // // Function: InetFreeEncodedObject // // Synopsis: free encoded object retrieved via InetRetrieveEncodedObject // //---------------------------------------------------------------------------- VOID WINAPI InetFreeEncodedObject ( IN LPCSTR pszObjectOid, IN PCRYPT_BLOB_ARRAY pObject, IN LPVOID pvFreeContext ) { assert( pvFreeContext == NULL ); InetFreeCryptBlobArray( pObject ); } //+--------------------------------------------------------------------------- // // Function: InetCancelAsyncRetrieval // // Synopsis: cancel asynchronous object retrieval // //---------------------------------------------------------------------------- BOOL WINAPI InetCancelAsyncRetrieval ( IN HCRYPTASYNC hAsyncRetrieve ) { SetLastError( (DWORD) E_NOTIMPL ); return( FALSE ); } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::CInetSynchronousRetriever, public // // Synopsis: Constructor // //---------------------------------------------------------------------------- CInetSynchronousRetriever::CInetSynchronousRetriever () { m_cRefs = 1; } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::~CInetSynchronousRetriever, public // // Synopsis: Destructor // //---------------------------------------------------------------------------- CInetSynchronousRetriever::~CInetSynchronousRetriever () { } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::AddRef, public // // Synopsis: IRefCountedObject::AddRef // //---------------------------------------------------------------------------- VOID CInetSynchronousRetriever::AddRef () { InterlockedIncrement( (LONG *)&m_cRefs ); } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::Release, public // // Synopsis: IRefCountedObject::Release // //---------------------------------------------------------------------------- VOID CInetSynchronousRetriever::Release () { if ( InterlockedDecrement( (LONG *)&m_cRefs ) == 0 ) { delete this; } } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::RetrieveObjectByUrl, public // // Synopsis: IObjectRetriever::RetrieveObjectByUrl // //---------------------------------------------------------------------------- BOOL CInetSynchronousRetriever::RetrieveObjectByUrl ( LPCSTR pszUrl, LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID* ppvObject, PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject, LPVOID* ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { BOOL fResult; DWORD LastError = 0; HINTERNET hInetSession = NULL; CHAR pszCanonicalUrl[INTERNET_MAX_PATH_LENGTH+1]; assert( hAsyncRetrieve == NULL ); fResult = InetGetBindings( pszUrl, dwRetrievalFlags, dwTimeout, &hInetSession, INTERNET_MAX_PATH_LENGTH+1, pszCanonicalUrl ); #if DBG if ( fResult == TRUE ) { printf( "Canonical URL to retrieve: %s\n", pszCanonicalUrl ); } #endif if ( fResult == TRUE ) { fResult = InetSendReceiveUrlRequest( hInetSession, pszCanonicalUrl, dwRetrievalFlags, pCredentials, (PCRYPT_BLOB_ARRAY)ppvObject, pAuxInfo ); } if ( fResult == TRUE ) { *ppfnFreeObject = InetFreeEncodedObject; *ppvFreeContext = NULL; } else { LastError = GetLastError(); } InetFreeBindings( hInetSession ); SetLastError( LastError ); return( fResult ); } //+--------------------------------------------------------------------------- // // Member: CInetSynchronousRetriever::CancelAsyncRetrieval, public // // Synopsis: IObjectRetriever::CancelAsyncRetrieval // //---------------------------------------------------------------------------- BOOL CInetSynchronousRetriever::CancelAsyncRetrieval () { SetLastError( (DWORD) E_NOTIMPL ); return( FALSE ); } //+--------------------------------------------------------------------------- // // Function: InetGetBindings // // Synopsis: get the session bindings // //---------------------------------------------------------------------------- BOOL InetGetBindings ( LPCSTR pszUrl, DWORD dwRetrievalFlags, DWORD dwTimeout, HINTERNET* phInetSession, DWORD cbCanonicalUrl, LPSTR pszCanonicalUrl ) { BOOL fResult = TRUE; DWORD LastError = 0; HINTERNET hInetSession; DWORD dwSessionFlags = 0; // // Create and configure the session handle // if ( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) { dwSessionFlags |= INTERNET_FLAG_ASYNC; } if ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) { dwSessionFlags |= INTERNET_FLAG_OFFLINE; } hInetSession = InternetOpen( "CryptRetrieveObjectByUrl::InetSchemeProvider", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, dwSessionFlags ); if ( hInetSession == NULL ) { return( FALSE ); } #if ASYNC_RETRIEVAL_SUPPORTED if ( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) { if ( InternetSetStatusCallback( hInetSession, InetAsyncStatusCallback ) == INTERNET_INVALID_STATUS_CALLBACK ) { SetLastError( (DWORD)INTERNET_INVALID_STATUS_CALLBACK ); fResult = FALSE; } } #endif if ( ( fResult == TRUE ) && ( dwTimeout != 0 ) ) { DWORD dwOptionValue; dwOptionValue = 0; fResult = InternetSetOption( hInetSession, INTERNET_OPTION_CONNECT_RETRIES, &dwOptionValue, sizeof( DWORD ) ); dwOptionValue = dwTimeout; if ( fResult == TRUE ) { fResult = InternetSetOption( hInetSession, INTERNET_OPTION_CONNECT_TIMEOUT, &dwOptionValue, sizeof( DWORD ) ); } if ( fResult == TRUE ) { fResult = InternetSetOption( hInetSession, INTERNET_OPTION_CONTROL_SEND_TIMEOUT, &dwOptionValue, sizeof( DWORD ) ); } if ( fResult == TRUE ) { fResult = InternetSetOption( hInetSession, INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT, &dwOptionValue, sizeof( DWORD ) ); } if ( fResult == TRUE ) { fResult = InternetSetOption( hInetSession, INTERNET_OPTION_DATA_SEND_TIMEOUT, &dwOptionValue, sizeof( DWORD ) ); } if ( fResult == TRUE ) { fResult = InternetSetOption( hInetSession, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, &dwOptionValue, sizeof( DWORD ) ); } } if ( fResult == TRUE ) { BOOL fDisableAutodial = TRUE; fResult = InternetSetOption( hInetSession, INTERNET_OPTION_DISABLE_AUTODIAL, &fDisableAutodial, sizeof( BOOL ) ); } //we turn off the auto proxy config since it will show a //dialogue, which will hang a service (lsa.exe) /* if( fResult == TRUE ) { dwSize=sizeof(IntOptList); memset(&IntOptList, 0, sizeof(IntOptList)); IntOptList.dwSize=sizeof(IntOptList); IntOptList.pszConnection=NULL; IntOptList.dwOptionCount=1; IntOptList.pOptions=&IntOption; memset(&IntOption, 0, sizeof(IntOption)); IntOption.dwOption=INTERNET_PER_CONN_FLAGS; fResult=InternetQueryOption( hInetSession, INTERNET_OPTION_PER_CONNECTION_OPTION, &IntOptList, &dwSize); if(fResult == TRUE) { IntOption.Value.dwValue &= ~(PROXY_TYPE_AUTO_DETECT | PROXY_TYPE_AUTO_PROXY_URL); fResult=InternetSetOption( hInetSession, INTERNET_OPTION_PER_CONNECTION_OPTION, &IntOptList, dwSize); } } */ // // Canonicalize the URL // if ( fResult == TRUE ) { fResult = InternetCanonicalizeUrlA( pszUrl, pszCanonicalUrl, &cbCanonicalUrl, 0 ); } if ( fResult == TRUE ) { *phInetSession = hInetSession; } else { LastError = GetLastError(); InternetCloseHandle( hInetSession ); } SetLastError( LastError ); return( fResult ); } //+--------------------------------------------------------------------------- // // Function: InetFreeBindings // // Synopsis: free the inet session bindings // //---------------------------------------------------------------------------- VOID InetFreeBindings ( HINTERNET hInetSession ) { if ( hInetSession != NULL ) { InternetCloseHandle( hInetSession ); } } //+--------------------------------------------------------------------------- // // Function: InetSendReceiveUrlRequest // // Synopsis: synchronous processing of an URL via WinInet // //---------------------------------------------------------------------------- BOOL InetSendReceiveUrlRequest ( HINTERNET hInetSession, LPSTR pszCanonicalUrl, DWORD dwRetrievalFlags, PCRYPT_CREDENTIALS pCredentials, PCRYPT_BLOB_ARRAY pcba, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { BOOL fResult = TRUE; BOOL fDataAvailable = TRUE; DWORD LastError = 0; HINTERNET hInetConnect; HINTERNET hInetFile; DWORD dwOpenFlags = 0; ULONG cbRead; ULONG cbData; ULONG cb; ULONG cbPerRead; LPBYTE pb; CRYPT_PASSWORD_CREDENTIALSA PasswordCredentials; BOOL fFreeCredentials = FALSE; CHAR pszServer[MAX_PATH + 1]; URL_COMPONENTSA UrlComponents; DWORD dwService; PCRYPTNET_CANCEL_BLOCK pCancelBlock=NULL; memset( &PasswordCredentials, 0, sizeof( PasswordCredentials ) ); PasswordCredentials.cbSize = sizeof( PasswordCredentials ); if ( SchemeGetPasswordCredentialsA( pCredentials, &PasswordCredentials, &fFreeCredentials ) == FALSE ) { return( FALSE ); } memset( &UrlComponents, 0, sizeof( UrlComponents ) ); UrlComponents.dwStructSize = sizeof( UrlComponents ); UrlComponents.dwHostNameLength = MAX_PATH; UrlComponents.lpszHostName = pszServer; if ( InternetCrackUrlA( pszCanonicalUrl, 0, 0, &UrlComponents ) == FALSE ) { return( FALSE ); } switch ( UrlComponents.nScheme ) { case INTERNET_SCHEME_HTTP: case INTERNET_SCHEME_HTTPS: dwService = INTERNET_SERVICE_HTTP; break; case INTERNET_SCHEME_FTP: dwService = INTERNET_SERVICE_FTP; break; case INTERNET_SCHEME_GOPHER: dwService = INTERNET_SERVICE_GOPHER; break; default: SetLastError( (DWORD) E_INVALIDARG ); return( FALSE ); } if ( ( hInetConnect = InternetConnect( hInetSession, UrlComponents.lpszHostName, UrlComponents.nPort, PasswordCredentials.pszUsername, PasswordCredentials.pszPassword, dwService, 0, 0 ) ) == NULL ) { return( FALSE ); } if ( fFreeCredentials == TRUE ) { SchemeFreePasswordCredentialsA( &PasswordCredentials ); } if ( dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT ) { dwOpenFlags |= INTERNET_FLAG_DONT_CACHE; } if ( dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL ) { dwOpenFlags |= INTERNET_FLAG_RELOAD; } if ( dwRetrievalFlags & CRYPT_NO_AUTH_RETRIEVAL ) { dwOpenFlags |= INTERNET_FLAG_NO_AUTH; } // We hope that INTERNET_FLAG_EXISTING_CONNECT will cause the // previous InternetConnect handle we opened to be used so that // the appropriate username and password will be set. If not // we will have to implement access to each of the protocols // ourselves and that would make me very unhappy :-( dwOpenFlags |= INTERNET_FLAG_RAW_DATA | INTERNET_FLAG_EXISTING_CONNECT; hInetFile = InternetOpenUrl( hInetSession, pszCanonicalUrl, "Accept: */*\r\n", (DWORD) -1L, dwOpenFlags, 0 ); if ( hInetFile == NULL ) { LastError = GetLastError(); InternetCloseHandle( hInetConnect ); SetLastError( LastError ); return( FALSE ); } if ( ( ( UrlComponents.nScheme == INTERNET_SCHEME_HTTP ) || ( UrlComponents.nScheme == INTERNET_SCHEME_HTTPS ) ) && ( !( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) ) ) { DWORD dwStatus; DWORD dwSizeofStatus = sizeof( dwStatus ); if ( HttpQueryInfo( hInetFile, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, &dwStatus, &dwSizeofStatus, NULL ) == FALSE ) { dwStatus = HTTP_STATUS_OK; } if ( dwStatus != HTTP_STATUS_OK ) { InternetCloseHandle( hInetFile ); InternetCloseHandle( hInetConnect ); SetLastError( dwStatus ); return( FALSE ); } } cbRead = 0; cb = INET_INITIAL_DATA_BUFFER_SIZE; pb = CCryptBlobArray::AllocBlob( cb ); if ( pb == NULL ) { fResult = FALSE; SetLastError( (DWORD) E_OUTOFMEMORY ); } pCancelBlock=(PCRYPTNET_CANCEL_BLOCK)I_CryptGetTls(hCryptNetCancelTls); while ( ( fResult == TRUE ) && ( fDataAvailable == TRUE ) ) { if(pCancelBlock) { if(pCancelBlock->pfnCancel(0, pCancelBlock->pvArg)) fResult=FALSE; } if(FALSE == fResult) { SetLastError((DWORD) ERROR_CANCELLED); } else { fDataAvailable = InternetQueryDataAvailable( hInetFile, &cbData, 0, 0 ); if ( ( fDataAvailable == TRUE ) && ( cbData == 0 ) ) { fDataAvailable = FALSE; } if ( fDataAvailable == TRUE ) { if ( cb < ( cbRead + cbData ) ) { pb = CCryptBlobArray::ReallocBlob( pb, cb + cbData + INET_GROW_DATA_BUFFER_SIZE ); if ( pb != NULL ) { cb += cbData + INET_GROW_DATA_BUFFER_SIZE; } else { fResult = FALSE; SetLastError( (DWORD) E_OUTOFMEMORY ); } } fResult = InternetReadFile( hInetFile, ( pb+cbRead ), cbData, &cbPerRead ); if ( fResult == TRUE ) { cbRead += cbPerRead; } } } } if ( fResult == TRUE ) { if ( !( dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT ) ) { fResult = SchemeRetrieveCachedAuxInfo ( pszCanonicalUrl, dwRetrievalFlags, pAuxInfo ); } else { fResult = SchemeRetrieveUncachedAuxInfo( pAuxInfo ); } } if ( fResult == TRUE ) { CCryptBlobArray cba( 1, 1, fResult ); if ( fResult == TRUE ) { fResult = cba.AddBlob( cbRead, pb, FALSE ); } if ( fResult == TRUE ) { cba.GetArrayInNativeForm( pcba ); } else { cba.FreeArray( FALSE ); } } if ( fResult != TRUE ) { if ( pb != NULL ) { CCryptBlobArray::FreeBlob( pb ); } LastError = GetLastError(); } InternetCloseHandle( hInetFile ); InternetCloseHandle( hInetConnect ); SetLastError( LastError ); return( fResult ); } //+--------------------------------------------------------------------------- // // Function: InetFreeCryptBlobArray // // Synopsis: free the crypt blob array // //---------------------------------------------------------------------------- VOID InetFreeCryptBlobArray ( PCRYPT_BLOB_ARRAY pcba ) { CCryptBlobArray cba( pcba, 0 ); cba.FreeArray( TRUE ); } //+--------------------------------------------------------------------------- // // Function: InetAsyncStatusCallback // // Synopsis: status callback for async // //---------------------------------------------------------------------------- VOID WINAPI InetAsyncStatusCallback ( HINTERNET hInet, DWORD dwContext, DWORD dwInternetStatus, LPVOID pvStatusInfo, DWORD dwStatusLength ) { return; }