726 lines
24 KiB
C++
726 lines
24 KiB
C++
// This is a part of the Active Template Library.
|
|
// Copyright (C) Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLHTTP_H__
|
|
#define __ATLHTTP_H__
|
|
|
|
#pragma once
|
|
#ifndef __CPPUNWIND
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4702)
|
|
#endif
|
|
#ifndef _WINSOCKAPI_
|
|
#include <winsock2.h>
|
|
#endif
|
|
#include <atlutil.h>
|
|
#include <atlisapi.h>
|
|
#include <atlcoll.h>
|
|
#include <atlfile.h>
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
#include <atlenc.h>
|
|
#ifndef _ATL_NO_DEFAULT_LIBS
|
|
#pragma comment(lib, "ws2_32.lib")
|
|
#pragma comment(lib, "SECUR32.LIB")
|
|
#endif // !_ATL_NO_DEFAULT_LIBS
|
|
|
|
#include <atlspriv.h>
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible
|
|
#pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible
|
|
|
|
#pragma pack(push,_ATL_PACKING)
|
|
namespace ATL {
|
|
|
|
template <class TSocketClass>
|
|
class CAtlHttpClientT;
|
|
class CAtlBaseAuthObject;
|
|
|
|
enum status_headerparse{
|
|
ATL_HEADER_PARSE_COMPLETE=0,
|
|
ATL_HEADER_PARSE_HEADERNOTCOMPLETE,
|
|
ATL_HEADER_PARSE_HEADERERROR
|
|
};
|
|
|
|
enum readstate{rs_init=0, rs_readheader, rs_scanheader, rs_readbody, rs_complete};
|
|
|
|
#define ATL_HEADER_END "\r\n\r\n"
|
|
#define ATL_HEADER_END_LEN 4
|
|
#define ATL_DW_HEADER_END 0x0a0d0a0d
|
|
#define ATL_FIELDNAME_DELIMITER _T(':')
|
|
#define ATL_MAX_FIELDNAME_LEN 1024
|
|
#define ATL_MAX_VALUE_LEN 1024
|
|
#define ATL_AUTH_HDR_SIZE 1024
|
|
#define ATL_READ_BUFF_SIZE 2048
|
|
#define ATL_INVALID_STATUS -1
|
|
#define ATL_HTTP_HEADER _T(" HTTP/1.1\r\n")
|
|
#define ATL_HTTP_HEADER_PROXY _T(" HTTP/1.1\r\n")
|
|
#ifndef ATL_HTTP_USERAGENT
|
|
#define ATL_HTTP_USERAGENT _T("User-Agent: Microsoft-ATL-Native/") _T(_ATL_VER_RBLD) _T("\r\n")
|
|
#endif
|
|
|
|
#define ATL_IS_INVALIDCREDHANDLE(x) ((x.dwLower==0xFFFFFFFF) && (x.dwUpper==0xFFFFFFFF))
|
|
#define ATL_HTTP_AUTHTYPE_NTLM _T("NTLM")
|
|
#define ATL_HTTP_AUTHTYPE_BASIC _T("BASIC")
|
|
#define ATL_HTTP_METHOD_GET _T("GET")
|
|
#define ATL_HTTP_METHOD_POST _T("POST")
|
|
|
|
#ifndef MAX_REALM_LEN
|
|
#define MAX_REALM_LEN 1024
|
|
#endif
|
|
|
|
#ifndef _ATL_MAX_AUTH_BUFF
|
|
#define _ATL_MAX_AUTH_BUFF 512
|
|
#endif
|
|
|
|
__interface IAuthInfo;
|
|
typedef bool (WINAPI *PFNATLCHUNKEDCB)(BYTE** ppData, DWORD *pdwSize, DWORD_PTR dwParam);
|
|
typedef bool (WINAPI *PFNATLSTATUSCALLBACK)(DWORD dwBytesSent, DWORD_PTR dwParam);
|
|
|
|
#define ATL_HTTP_FLAG_AUTO_REDIRECT 0x1
|
|
#define ATL_HTTP_FLAG_PROCESS_RESULT 0x2
|
|
#define ATL_HTTP_FLAG_SEND_CALLBACK 0x4
|
|
#define ATL_HTTP_FLAG_SEND_BLOCKS 0x8
|
|
#define ATL_HTTP_FLAG_INVALID_FLAGS 0xFFFFFFFF
|
|
|
|
#ifndef ATL_HTTP_DEFAULT_BLOCK_SIZE
|
|
#define ATL_HTTP_DEFAULT_BLOCK_SIZE 4096
|
|
#endif
|
|
|
|
#define ATL_HTTP_CLIENT_EMPTY_READ_RETRIES 5
|
|
|
|
struct ATL_NAVIGATE_DATA
|
|
{
|
|
LPCTSTR szExtraHeaders;
|
|
LPCTSTR szMethod;
|
|
LPCTSTR szDataType;
|
|
DWORD dwDataLen;
|
|
DWORD dwFlags;
|
|
DWORD dwTimeout;
|
|
DWORD dwSendBlockSize;
|
|
DWORD dwReadBlockSize;
|
|
DWORD_PTR m_lParamSend;
|
|
DWORD_PTR m_lParamRead;
|
|
DWORD_PTR m_lParamChunkCB;
|
|
short nPort;
|
|
BYTE *pData;
|
|
PFNATLCHUNKEDCB pfnChunkCallback;
|
|
PFNATLSTATUSCALLBACK pfnSendStatusCallback;
|
|
PFNATLSTATUSCALLBACK pfnReadStatusCallback;
|
|
};
|
|
|
|
class CAtlNavigateData : public ATL_NAVIGATE_DATA
|
|
{
|
|
public:
|
|
CAtlNavigateData() throw(); // public construction
|
|
CAtlNavigateData(const CAtlNavigateData &rhs);
|
|
CAtlNavigateData(const ATL_NAVIGATE_DATA &rhs);
|
|
CAtlNavigateData& operator=(const CAtlNavigateData &rhs);
|
|
CAtlNavigateData& operator=(const ATL_NAVIGATE_DATA &rhs);
|
|
DWORD SetFlags(DWORD dwNewFlags) throw(); // set all flags
|
|
DWORD GetFlags() throw(); // get value of flags
|
|
DWORD AddFlags(DWORD dwFlagsToAdd) throw(); // add one or more flags to existing flags
|
|
DWORD RemoveFlags(DWORD dwFlagsToRemove) throw(); // remove one or more flags from existing flags
|
|
LPCTSTR SetExtraHeaders(LPCTSTR szNewHeaders) throw(); // set the extra request headers
|
|
LPCTSTR GetExtraHeaders() throw(); // get the extra request headers
|
|
LPCTSTR SetMethod(LPCTSTR szNewMethod) throw(); // set the HTTP request method
|
|
LPCTSTR GetMethod() throw(); // get the HTTP request method
|
|
short SetPort(short newPort) throw(); // set the TCP port for this request
|
|
short GetPort() throw(); // get the TCP port for this request
|
|
void SetPostData(BYTE *pData, DWORD dwDataLen, LPCTSTR szDataType) throw(); // Set data to be sent as the reqeust entity body
|
|
DWORD SetSocketTimeout(DWORD dwNewTimeout) throw(); // Set the timeout for this socket
|
|
DWORD GetSocketTimeout() throw(); // Get the timeout for this socket
|
|
DWORD SetSendBlockSize(DWORD dwBlockSize) throw(); // Set the size of the blocks used to send data
|
|
DWORD GetSendBlockSize() throw(); // get the size of the blocks used to send data
|
|
DWORD SetReadBlockSize(DWORD dwBlockSize) throw(); // Set the size of the blocks used to send data
|
|
DWORD GetReadBlockSize() throw(); // get the size of the blocks used to send data
|
|
PFNATLCHUNKEDCB SetChunkCallback(PFNATLCHUNKEDCB pfn, DWORD_PTR dwParam) throw(); // set the callback function used for sending chunked data
|
|
PFNATLCHUNKEDCB GetChunkCallback() throw(); // get the chunked callback function
|
|
PFNATLSTATUSCALLBACK SetSendStatusCallback(PFNATLSTATUSCALLBACK pfn, DWORD_PTR dwData) throw(); // sets a function pointer to be called after bytes are sent over the socket
|
|
PFNATLSTATUSCALLBACK GetSendStatusCallback() throw(); // returns current status callback function
|
|
PFNATLSTATUSCALLBACK SetReadStatusCallback(PFNATLSTATUSCALLBACK pfn, DWORD_PTR dwData) throw();
|
|
PFNATLSTATUSCALLBACK GetReadStatusCallback() throw();
|
|
};
|
|
|
|
template <class TSocketClass>
|
|
class CAtlHttpClientT :
|
|
private TSocketClass
|
|
{
|
|
public:
|
|
CAtlHttpClientT() throw();
|
|
virtual ~CAtlHttpClientT()
|
|
{
|
|
}
|
|
|
|
// Use these functions to send an HTTP request and retrieve
|
|
// the response.
|
|
bool Navigate(
|
|
const CUrl* pUrl,
|
|
ATL_NAVIGATE_DATA *pNavData = NULL
|
|
) throw(...);
|
|
|
|
bool Navigate(
|
|
LPCTSTR szServer,
|
|
LPCTSTR szPath,
|
|
ATL_NAVIGATE_DATA *pNavData = NULL
|
|
) throw(...);
|
|
|
|
bool Navigate(
|
|
LPCTSTR szURL,
|
|
ATL_NAVIGATE_DATA *pNavData = NULL
|
|
) throw(...);
|
|
|
|
|
|
// Performs navigation, sending data with Transfer-Coding: chunked
|
|
bool NavigateChunked(
|
|
const CUrl *pUrl,
|
|
ATL_NAVIGATE_DATA *pData
|
|
) throw();
|
|
|
|
bool NavigateChunked(
|
|
LPCTSTR szServer,
|
|
LPCTSTR szPath,
|
|
ATL_NAVIGATE_DATA *pNavData
|
|
) throw();
|
|
|
|
bool NavigateChunked(
|
|
LPCTSTR szURL,
|
|
ATL_NAVIGATE_DATA *pNavData
|
|
) throw();
|
|
|
|
// Use to set/retrieve information about the proxy server used
|
|
// when making this request via a proxy server.
|
|
bool SetProxy(LPCTSTR szProxy = NULL, short nProxyPort = 0) throw();
|
|
void RemoveProxy() throw();
|
|
LPCTSTR GetProxy() const throw();
|
|
short GetProxyPort() const throw();
|
|
|
|
// Use these functions to add/remove/find objects that will
|
|
// be used to authorize request when a 401 Not Authorized response
|
|
// is received. This class maps these objects by scheme name in map.
|
|
// Override NegotiateAuth to change the way authorization negotiation occurs.
|
|
bool AddAuthObj(LPCTSTR szScheme, CAtlBaseAuthObject *pObject, IAuthInfo *pInfo=NULL) throw();
|
|
const CAtlBaseAuthObject* FindAuthObject(LPCTSTR szScheme) throw();
|
|
bool RemoveAuthObject(LPCTSTR szScheme) throw();
|
|
virtual bool NegotiateAuth(bool bProxy) throw();
|
|
|
|
|
|
// Retrieve the value of a response header
|
|
bool GetHeaderValue(LPCTSTR szName, CString& strValue) const throw();
|
|
bool GetHeaderValue(__in_z LPCTSTR szName, __out_ecount_part_z_opt(*pdwLen, *pdwLen) LPTSTR szBuffer, __inout DWORD *pdwLen) const throw();
|
|
|
|
DWORD GetResponseLength() throw(); // Get the number of bytes in the response
|
|
const BYTE* GetResponse() throw(); // Get the entire response
|
|
DWORD GetBodyLength() const throw(); // Get the length of the body of the response (everything after the \r\n\r\n)
|
|
const BYTE* GetBody() throw(); // Get the body of the response (length is determined by GetBodyLength())
|
|
DWORD GetRawResponseHeaderLength() throw(); // Get the length of the raw request headers
|
|
bool GetRawResponseHeader(LPBYTE szBuffer, DWORD *pdwLen) throw(); // Get the raw request headers
|
|
LPCURL GetCurrentUrl() const throw(); // Get a pointer to the current URL for this request
|
|
DWORD GetFlags() const throw(); // Retrieve flags used for processing this request
|
|
int GetStatus() throw(); // Get the HTTP status code that resulted from making this request
|
|
LPCTSTR GetMethod() throw(); // Get the HTTP method used for making this request
|
|
BYTE* GetPostData() throw(); // Get a pointer to raw data being sent with this request
|
|
DWORD GetPostDataLen() throw(); // Get the length of the raw data sent with this request
|
|
LPCTSTR GetPostDataType() throw(); // Get the data type (sent as Content-Type header) for this request
|
|
DWORD GetLastError() throw(); // Retrieves errors from the underlying socket
|
|
const SOCKET& GetSocket() throw(); // Retrieves the underlying socket. Be careful!
|
|
void Close() throw(); // Close the connection
|
|
DWORD SetSocketTimeout(DWORD dwNewTimeout) throw(); // Sets a new socket timeout, returns the old timeout.
|
|
DWORD GetSocketTimeout() throw(); // retrieves the current socket timeout
|
|
void AuthProtocolFailed(LPCTSTR szProto) throw(); // notifies us of failure to connect with the named protocol
|
|
const ATL_NAVIGATE_DATA* GetCurrentNavdata();
|
|
enum HTTP_RESPONSE_READ_STATUS
|
|
{
|
|
RR_OK = 0, // response was successfully processed
|
|
RR_FAIL, // an unknown error occurred reading the HTTP response
|
|
RR_STATUS_INVALID, // could not parse the status line
|
|
RR_PARSEHEADERS_FAILED, // failed to parse HTTP response headers
|
|
RR_READSOCKET_FAILED, // failed to read response data from socket
|
|
RR_READBODY_FAILED, // failed to successfully read the entity body of the HTTP response
|
|
RR_READCHUNKEDBODY_FAILED, // failed to read a 'Transfer-Encoding: chunked' response body
|
|
RR_NOT_READ // we haven't started reading the response.
|
|
};
|
|
HTTP_RESPONSE_READ_STATUS GetResponseStatus();
|
|
|
|
|
|
// Implementation
|
|
HTTP_RESPONSE_READ_STATUS ReadHttpResponse() throw();
|
|
void ResetConnection() throw();
|
|
bool ProcessStatus(DWORD dwFlags) throw();
|
|
bool BuildRequest(/*out*/CString *pstrRequest,
|
|
LPCTSTR szDataType=NULL,
|
|
LPCTSTR szExtraHeaders=NULL) throw();
|
|
|
|
void SetSilentLogonOk(bool bSet)
|
|
{
|
|
m_bSilentLogonOk = bSet;
|
|
}
|
|
protected:
|
|
DWORD WriteWithNoData(LPCSTR pRequest, DWORD dwRequestLen);
|
|
DWORD WriteWithCallback(LPCSTR pRequest, DWORD dwRequestLen);
|
|
DWORD WriteWithChunks(LPCSTR pRequest, DWORD dwRequestLen);
|
|
DWORD WriteWithData(LPCSTR pRequest, DWORD dwRequestLen);
|
|
bool SetDefaultUrl(LPCTSTR szUrl, short nPortNumber=ATL_URL_DEFAULT_HTTP_PORT) throw();
|
|
bool SetDefaultUrl(LPCURL pUrl, short nPortNumber=ATL_URL_DEFAULT_HTTP_PORT) throw();
|
|
bool SetDefaultMethod(LPCTSTR szMethod) throw();
|
|
void InitializeObject() throw();
|
|
void ResetRequest() throw();
|
|
bool ReadSocket() throw();
|
|
unsigned char* FindHeaderEnd(unsigned char** ppBegin) throw();
|
|
bool LookupRegProxy() throw();
|
|
bool DisconnectIfRequired() throw();
|
|
bool ConnectSocket() throw();
|
|
|
|
long GetContentLength() throw();
|
|
LPCSTR NextLine(BYTE* pCurr) throw();
|
|
bool IsMsgBodyChunked() throw();
|
|
LPCSTR FindEndOfHeader(LPCSTR pszStart) throw();
|
|
bool DecodeHeader(LPCSTR pHeaderStart, LPCSTR pHeaderEnd) throw();
|
|
virtual void OnSetCookie(LPCTSTR /*szCookie*/) throw();
|
|
LPCSTR ParseStatusLine(BYTE* pBuffer) throw();
|
|
int CrackResponseHeader(LPCSTR pBuffer, /*out*/ LPCSTR *pEnd) throw();
|
|
bool ReadBody(int nContentLen, int nCurrentBodyLen) throw();
|
|
bool ReadChunkedBody() throw();
|
|
bool ReconnectIfRequired() throw();
|
|
bool CompleteURL(CString& strURL) throw();
|
|
bool ProcessObjectMoved() throw();
|
|
bool _SetDefaultUrl(LPCTSTR szURL, short nPort) throw();
|
|
|
|
enum CHUNK_STATE{
|
|
READ_CHUNK_SIZE, // need to read the size of a chunk.
|
|
READ_CHUNK_SIZE_FOOTER,
|
|
READ_CHUNK_DATA, // need to read the actual data
|
|
READ_CHUNK_DATA_FOOTER, // need to read the chunk footer.
|
|
READ_CHUNK_TRAILER, // Read the trailer headers at the end of the chunk data
|
|
READ_CHUNK_TRAILER_FOOTER, // read the final crlf
|
|
CHUNK_READ_DATA_COMPLETE, // done reading chunk data.
|
|
};
|
|
|
|
enum CHUNK_LEX_RESULT{
|
|
LEX_OK,
|
|
LEX_OUTOFDATA,
|
|
LEX_ERROR,
|
|
LEX_TRAILER_COMPLETE
|
|
};
|
|
|
|
CHUNK_LEX_RESULT get_chunked_size(__deref_inout char *&pBuffStart, __deref_inout char *&pBuffEnd, __inout long* pnChunkSize) throw();
|
|
bool move_leftover_bytes(__in_ecount(nLen) char *pBufferStart, __in int nLen, __deref_inout char *&pBuffStart, __deref_inout char *&pBuffEnd) throw();
|
|
CHUNK_LEX_RESULT get_chunked_data(__deref_inout char *&pBufferStart, __deref_inout char *&pBufferEnd, long nChunkSize,
|
|
__deref_out_ecount_part(*pnDataLen, *pnDataLen) char **ppDataStart, __inout long *pnDataLen) throw();
|
|
CHUNK_LEX_RESULT consume_chunk_trailer(__deref_inout char *&pBufferStart, __deref_inout char *pBufferEnd) throw();
|
|
CHUNK_LEX_RESULT consume_chunk_footer(__deref_inout char *&pBufferStart, __deref_inout char *&pBufferEnd) throw();
|
|
|
|
typedef CAtlMap<
|
|
CString,
|
|
CString,
|
|
CStringElementTraitsI<CString>,
|
|
CStringElementTraitsI<CString>
|
|
> HeaderMapType;
|
|
|
|
typedef CAtlMap <
|
|
CString,
|
|
CAtlBaseAuthObject*,
|
|
CStringElementTraitsI<CString>
|
|
> AuthMapType;
|
|
|
|
typedef CAtlArray<
|
|
CString,
|
|
CStringElementTraitsI<CString>
|
|
> AuthListType;
|
|
|
|
HeaderMapType m_HeaderMap; // Map of response headers
|
|
AuthMapType m_AuthMap; // Map of pointers to authorization objects.
|
|
AuthListType m_AuthTypes; // list of authorization types the server is willing to use.
|
|
BOOL m_bSilentLogonOk;
|
|
CAtlIsapiBuffer<> m_current; // The entire response
|
|
CUrl m_urlCurrent; // URL of current request
|
|
|
|
CString m_strMethod; // Current request method.
|
|
CString m_strProxy; // Path to current proxy server.
|
|
|
|
long m_nStatus; // Current response status (from status line)
|
|
short m_nProxyPort; // Port used on current proxy server
|
|
DWORD m_dwBodyLen; // Length of body
|
|
DWORD m_dwHeaderLen; // Length of current raw headers
|
|
DWORD m_dwHeaderStart;
|
|
BYTE *m_pCurrent;
|
|
BYTE *m_pEnd; // the end of the data we've read fromt he socket;
|
|
ATL_NAVIGATE_DATA *m_pNavData;
|
|
HTTP_RESPONSE_READ_STATUS m_LastResponseParseError;
|
|
}; //CAtlHttpClientT
|
|
typedef CAtlHttpClientT<ZEvtSyncSocket> CAtlHttpClient;
|
|
|
|
|
|
// Interface used to acquire authentication information from clients
|
|
__interface IAuthInfo
|
|
{
|
|
HRESULT GetPassword(__out_ecount_part_z_opt(*pdwBuffSize, *pdwBuffSize) LPTSTR szPwd, __inout DWORD *pdwBuffSize);
|
|
HRESULT GetUsername(__out_ecount_part_z_opt(*pdwBuffSize, *pdwBuffSize) LPTSTR szUid, __inout DWORD *pdwBuffSize);
|
|
HRESULT GetDomain(__out_ecount_part_z_opt(*pdwBuffSize, *pdwBuffSize) LPTSTR szDomain, __inout DWORD *pdwBuffSize);
|
|
};
|
|
typedef HRESULT (IAuthInfo::*PFNAUTHFUNC)(LPTSTR szPwd, DWORD *pdwSize);
|
|
|
|
// pure virtual class that describes required functions for authoriztion
|
|
// objects
|
|
class CAtlBaseAuthObject
|
|
{
|
|
public:
|
|
CAtlBaseAuthObject();
|
|
virtual bool Authenticate(LPCTSTR szAuthTypes, bool bProxy) = 0;
|
|
virtual void Init(CAtlHttpClient *pSocket, IAuthInfo *pAuthInfo) = 0;
|
|
bool m_bFailed;
|
|
};
|
|
|
|
// strings used for authentication.
|
|
extern __declspec(selectany)const TCHAR * const g_pszWWWAuthenticate = _T("www-authenticate");
|
|
extern __declspec(selectany)const TCHAR * const g_pszProxyAuthenticate = _T("proxy-authenticate");
|
|
|
|
// Performs NTLM authentication
|
|
class CNTLMAuthObject :
|
|
public CAtlBaseAuthObject
|
|
{
|
|
public:
|
|
virtual ~CNTLMAuthObject() throw();
|
|
CNTLMAuthObject() throw();
|
|
CNTLMAuthObject(IAuthInfo *pAuthInfo) throw();
|
|
void SetAuthInfo(IAuthInfo *pAuthInfo) throw();
|
|
bool GetCredentialNames(CString& theName);
|
|
|
|
// Implementation
|
|
// Called by the CAtlHttpClient class to authenticate a user.
|
|
virtual void Init(CAtlHttpClient *pSocket, IAuthInfo *pAuthInfo=NULL) throw();
|
|
|
|
// Called by the CAtlHttpClient class to initialize this authentication object.
|
|
virtual bool Authenticate(LPCTSTR szAuthTypes, bool bProxy) throw();
|
|
protected:
|
|
bool AcquireCredHandle() throw();
|
|
// This function creates an NTML Authorization header
|
|
// and sends it to the HTTP server.
|
|
bool SendSecurityInfo(SecBuffer *pSecBuffer, LPSTR *pszBuffer) throw();
|
|
bool DoNTLMAuthenticate() throw();
|
|
|
|
IAuthInfo *m_pAuthInfo;
|
|
CAtlHttpClient *m_pSocket;
|
|
CredHandle m_hCredentials;
|
|
int m_nMaxTokenSize;
|
|
TimeStamp m_ts;
|
|
bool m_bProxy;
|
|
static const char * const m_pszFmtWWW;
|
|
static const char * const m_pszFmtProxy;
|
|
CAtlNavigateData m_CurrentRequestData;
|
|
|
|
}; // CNTLMAuthObject
|
|
|
|
// Performs BASIC authentication for an CAtlHttpClient
|
|
// object. Caller must implement an IAuthInfo interface
|
|
// and pass it to this object before this object attempts
|
|
// to authenticate or authentication will fail.
|
|
class CBasicAuthObject :
|
|
public CAtlBaseAuthObject
|
|
{
|
|
public:
|
|
CBasicAuthObject() throw();
|
|
CBasicAuthObject(IAuthInfo *pAuthInfo) throw();
|
|
void SetAuthInfo(IAuthInfo *pAuthInfo) throw();
|
|
LPCTSTR GetRealm() throw(); // Retrieve's the realm being used.
|
|
|
|
// Implementation
|
|
// Called by the CAtlHttpClient class to authenticate a user.
|
|
virtual bool Authenticate(LPCTSTR szAuthTypes, bool bProxy) throw();
|
|
|
|
// Called by the CAtlHttpClient class to initialize this authentication object.
|
|
virtual void Init(CAtlHttpClient *pSocket, IAuthInfo *pAuthInfo=NULL) throw();
|
|
protected:
|
|
bool DoBasicAuthenticate() throw();
|
|
bool CrackRealm(LPCTSTR szHeader) throw();
|
|
|
|
IAuthInfo *m_pAuthInfo;
|
|
CAtlHttpClient *m_pClient;
|
|
TCHAR m_szRealm[MAX_REALM_LEN];
|
|
bool m_bProxy;
|
|
static const char * const m_pszFmtWWW;
|
|
static const char * const m_pszFmtProxy;
|
|
}; // CBasicAuthObject
|
|
|
|
__declspec(selectany)const char * const CBasicAuthObject::m_pszFmtWWW = "Authorization: Basic ";
|
|
__declspec(selectany)const char * const CBasicAuthObject::m_pszFmtProxy = "Proxy-Authorization: Basic ";
|
|
__declspec(selectany)const char * const CNTLMAuthObject::m_pszFmtWWW = "Authorization: NTLM %s\r\n";
|
|
__declspec(selectany)const char * const CNTLMAuthObject::m_pszFmtProxy = "Proxy-Authorization: NTLM %s\r\n";
|
|
|
|
typedef CTempBuffer<TCHAR, _ATL_MAX_AUTH_BUFF> CAuthInfoBuffType;
|
|
inline bool _AtlGetAuthInfoHelper(IAuthInfo *pObj, PFNAUTHFUNC pFunc, CAuthInfoBuffType& buff, DWORD *dwLen) throw()
|
|
{
|
|
ATLENSURE_RETURN_VAL(pObj, false);
|
|
ATLENSURE_RETURN_VAL(pFunc, false);
|
|
DWORD dwSize = _ATL_MAX_AUTH_BUFF;
|
|
bool bRet = true;
|
|
TCHAR *szValue = NULL;
|
|
_ATLTRY
|
|
{
|
|
szValue = buff.Allocate(_ATL_MAX_AUTH_BUFF);
|
|
HRESULT hr = E_FAIL;
|
|
if (szValue)
|
|
{
|
|
hr = (pObj->*pFunc)(szValue, &dwSize);
|
|
if (hr != S_OK)
|
|
{
|
|
if (hr == E_OUTOFMEMORY)
|
|
{
|
|
// buffer not big enough, try to allocate
|
|
szValue = buff.Reallocate(dwSize);
|
|
if (szValue)
|
|
{
|
|
// retry the call
|
|
if (S_OK != (pObj->*pFunc)(szValue, &dwSize))
|
|
bRet = false;
|
|
}
|
|
else
|
|
bRet = false;
|
|
}
|
|
else
|
|
bRet = false;
|
|
}
|
|
}
|
|
else
|
|
bRet = false;
|
|
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
bRet = false;
|
|
}
|
|
if (bRet)
|
|
*dwLen = (DWORD)_tcslen(szValue);
|
|
else
|
|
*dwLen = 0;
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// Security Service Provider Interface (sspi) Helper classes
|
|
// These classes are used as helpers for structures used in
|
|
// SSPI functions.
|
|
//
|
|
class CSecAuthIdentity : public SEC_WINNT_AUTH_IDENTITY_EX
|
|
{
|
|
public:
|
|
CSecAuthIdentity() throw()
|
|
{
|
|
Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
|
|
Length = sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
|
|
#ifdef _UNICODE
|
|
Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
|
#else
|
|
Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
|
#endif
|
|
}
|
|
|
|
|
|
bool Init(IAuthInfo *pAuthInfo) throw()
|
|
{
|
|
if (!pAuthInfo)
|
|
return false;
|
|
|
|
if (!_AtlGetAuthInfoHelper(pAuthInfo, &IAuthInfo::GetUsername, buffUserName, &UserLength))
|
|
return false;
|
|
|
|
if (!_AtlGetAuthInfoHelper(pAuthInfo, &IAuthInfo::GetPassword, buffPassword, &PasswordLength))
|
|
return false;
|
|
|
|
if (!_AtlGetAuthInfoHelper(pAuthInfo, &IAuthInfo::GetDomain, buffDomain, &DomainLength))
|
|
return false;
|
|
|
|
#ifndef _UNICODE
|
|
User = (unsigned char*)(char*)buffUserName;
|
|
Domain = DomainLength > 0 ? (unsigned char*)(char*)buffDomain : 0;
|
|
Password = PasswordLength > 0 ? (unsigned char*)(char*)buffPassword : 0;
|
|
#else
|
|
// have to cast to unsigned short *, because SEC_WINNT_AUTH_IDENTITY_EXW
|
|
// uses unsigned short instead of wchar_t
|
|
User = (unsigned short *)(wchar_t*)buffUserName;
|
|
Domain = DomainLength > 0 ? (unsigned short *)(wchar_t*)buffDomain : 0;
|
|
Password = PasswordLength > 0 ? (unsigned short *)(wchar_t*)buffPassword : 0;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
CAuthInfoBuffType buffUserName;
|
|
CAuthInfoBuffType buffPassword;
|
|
CAuthInfoBuffType buffDomain;
|
|
}; // CSecAuthIdentity
|
|
|
|
class CSecBuffer : public SecBuffer
|
|
{
|
|
public:
|
|
CSecBuffer() throw()
|
|
{
|
|
cbBuffer = 0;
|
|
BufferType = 0;
|
|
pvBuffer = NULL;
|
|
m_cbAlloc = 0;
|
|
}
|
|
|
|
~CSecBuffer() throw()
|
|
{
|
|
delete [] static_cast<unsigned char*>(pvBuffer);
|
|
}
|
|
|
|
bool SetSize(unsigned long nSize) throw()
|
|
{
|
|
if (!nSize)
|
|
return false;
|
|
|
|
if (pvBuffer)
|
|
{
|
|
delete [] static_cast<unsigned char*>(pvBuffer);
|
|
pvBuffer = NULL;
|
|
cbBuffer = 0;
|
|
m_cbAlloc = 0;
|
|
}
|
|
|
|
ATLTRY(pvBuffer = static_cast<void*>(new unsigned char[nSize]));
|
|
if (pvBuffer)
|
|
{
|
|
cbBuffer = nSize;
|
|
BufferType = SECBUFFER_TOKEN;
|
|
m_cbAlloc = cbBuffer;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ClearBuffer(unsigned long nSize) throw()
|
|
{
|
|
if(nSize > m_cbAlloc)
|
|
return false;
|
|
|
|
ZeroMemory(pvBuffer, nSize);
|
|
cbBuffer = nSize;
|
|
return true;
|
|
}
|
|
|
|
unsigned long Size()
|
|
{
|
|
return cbBuffer;
|
|
}
|
|
|
|
unsigned char *Buffer() throw()
|
|
{
|
|
return static_cast<unsigned char*>(pvBuffer);
|
|
}
|
|
|
|
operator SecBuffer*() throw()
|
|
{
|
|
return (SecBuffer*)this;
|
|
}
|
|
|
|
protected:
|
|
unsigned long m_cbAlloc;
|
|
|
|
}; // CSecBuffer
|
|
|
|
class CSecBufferDesc : public SecBufferDesc
|
|
{
|
|
public:
|
|
CSecBufferDesc() throw()
|
|
{
|
|
ulVersion = SECBUFFER_VERSION;
|
|
cBuffers = 0;
|
|
pBuffers = NULL;
|
|
}
|
|
|
|
~CSecBufferDesc() throw()
|
|
{
|
|
cBuffers = 0;
|
|
|
|
if (pBuffers)
|
|
{
|
|
CSecBuffer *psb = (CSecBuffer*)pBuffers;
|
|
delete [] psb;
|
|
}
|
|
}
|
|
|
|
// index is 0 based
|
|
CSecBuffer* Buffers(unsigned int i) throw()
|
|
{
|
|
if (i < cBuffers)
|
|
{
|
|
return (CSecBuffer*)(&pBuffers[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool AddBuffers(unsigned int nCount, unsigned int nBufferSize) throw()
|
|
{
|
|
if (!nCount)
|
|
return true;
|
|
|
|
if (cBuffers == 0)
|
|
{
|
|
CSecBuffer *pSecBuffer = NULL;
|
|
ATLTRY(pSecBuffer = new CSecBuffer[nCount]);
|
|
if (!pSecBuffer)
|
|
return false;
|
|
CAutoVectorPtr<CSecBuffer> spSecBuffer(pSecBuffer);
|
|
|
|
for (unsigned int i=0; i<nCount; i++)
|
|
{
|
|
if (!pSecBuffer[i].SetSize(nBufferSize))
|
|
return false;
|
|
}
|
|
cBuffers = nCount;
|
|
pBuffers = (SecBuffer*)spSecBuffer.Detach();
|
|
}
|
|
else // realloc
|
|
{
|
|
CSecBuffer *pSecBuffer = NULL;
|
|
ATLTRY(pSecBuffer = new CSecBuffer[nCount + cBuffers]);
|
|
if (!pSecBuffer)
|
|
return false;
|
|
CAutoVectorPtr<CSecBuffer> spSecBuffer(pSecBuffer);
|
|
Checked::memcpy_s(pSecBuffer, (nCount + cBuffers)*sizeof(CSecBuffer), pBuffers, cBuffers*sizeof(CSecBuffer));
|
|
delete [] pBuffers;
|
|
pBuffers=NULL;
|
|
|
|
// initialize new buffers
|
|
for (unsigned int i=0; i<nCount; i++)
|
|
{
|
|
if (!pSecBuffer[cBuffers+i].SetSize(nBufferSize))
|
|
return false;
|
|
}
|
|
pBuffers = spSecBuffer.Detach();
|
|
cBuffers += nCount;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
operator PSecBufferDesc() throw()
|
|
{
|
|
return static_cast<PSecBufferDesc>(this);
|
|
}
|
|
}; // CSecBufferDesc
|
|
|
|
} // namespace ATL
|
|
|
|
|
|
#include <atlhttp.inl>
|
|
|
|
#pragma pack(pop)
|
|
#pragma warning(pop)
|
|
|
|
#ifndef __CPPUNWIND
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
#endif // __ATLHTTP_H__
|