Leaked source code of windows server 2003
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.

540 lines
17 KiB

  1. /*****************************************************************************\
  2. * MODULE: anycon.cxx
  3. *
  4. * The module contains the base class for connections
  5. *
  6. * Copyright (C) 1997-1998 Microsoft Corporation
  7. *
  8. * History:
  9. * 07/31/98 Weihaic Created
  10. *
  11. \*****************************************************************************/
  12. #include "precomp.h"
  13. #include "priv.h"
  14. /******************************************************************************
  15. * Class Data Static Members
  16. *****************************************************************************/
  17. const DWORD CAnyConnection::gm_dwConnectTimeout = 30000; // Thirty second timeout on connect
  18. const DWORD CAnyConnection::gm_dwSendTimeout = 30000; // Thirty timeout on send timeout
  19. const DWORD CAnyConnection::gm_dwReceiveTimeout = 60000; // Thirty seconds on receive timeout
  20. const DWORD CAnyConnection::gm_dwSendSize = 0x10000; // We use a 16K sections when sending
  21. // data through WININET
  22. extern BOOL Ping (LPTSTR pszServerName);
  23. CAnyConnection::CAnyConnection (
  24. BOOL bSecure,
  25. INTERNET_PORT nServerPort,
  26. BOOL bIgnoreSecurityDlg,
  27. DWORD dwAuthMethod):
  28. m_lpszPassword (NULL),
  29. m_lpszUserName (NULL),
  30. m_hSession (NULL),
  31. m_hConnect (NULL),
  32. m_dwAccessFlag (INTERNET_OPEN_TYPE_PRECONFIG),
  33. m_bSecure (bSecure),
  34. m_bShowSecDlg (FALSE),
  35. m_dwAuthMethod (dwAuthMethod),
  36. m_bIgnoreSecurityDlg (bIgnoreSecurityDlg),
  37. m_bValid (FALSE)
  38. {
  39. if (!nServerPort) {
  40. if (bSecure) {
  41. m_nServerPort = INTERNET_DEFAULT_HTTPS_PORT;
  42. }
  43. else {
  44. m_nServerPort = INTERNET_DEFAULT_HTTP_PORT;
  45. }
  46. }
  47. else
  48. m_nServerPort = nServerPort;
  49. m_bValid = TRUE;
  50. }
  51. CAnyConnection::~CAnyConnection ()
  52. {
  53. if (m_hConnect) {
  54. (void) CAnyConnection::Disconnect ();
  55. }
  56. if (m_hSession) {
  57. (void) CAnyConnection::CloseSession ();
  58. }
  59. LocalFree (m_lpszPassword);
  60. m_lpszPassword = NULL;
  61. LocalFree (m_lpszUserName);
  62. m_lpszUserName = NULL;
  63. }
  64. HINTERNET
  65. CAnyConnection::OpenSession ()
  66. {
  67. m_hSession = InetInternetOpen(g_szUserAgent,
  68. m_dwAccessFlag,
  69. NULL,
  70. NULL,
  71. 0);
  72. if (m_hSession) { // Set up the callback function if successful
  73. // Also set an internet connection timeout for the session for when we try the
  74. // connection, should we do this instead of a ping?
  75. DWORD dwTimeout = gm_dwConnectTimeout;
  76. if (!InetInternetSetOption( m_hSession,
  77. INTERNET_OPTION_CONNECT_TIMEOUT,
  78. (LPVOID)&dwTimeout,
  79. sizeof(dwTimeout)
  80. ))
  81. goto Cleanup;
  82. // Now set the Send and Receive Timeout values
  83. dwTimeout = gm_dwSendTimeout;
  84. if (!InetInternetSetOption( m_hSession,
  85. INTERNET_OPTION_SEND_TIMEOUT,
  86. (LPVOID)&dwTimeout,
  87. sizeof(dwTimeout)
  88. ))
  89. goto Cleanup;
  90. dwTimeout = gm_dwReceiveTimeout;
  91. if (!InetInternetSetOption( m_hSession,
  92. INTERNET_OPTION_RECEIVE_TIMEOUT,
  93. (LPVOID)&dwTimeout,
  94. sizeof(dwTimeout)
  95. ))
  96. goto Cleanup;
  97. }
  98. return m_hSession;
  99. Cleanup:
  100. if (m_hSession) {
  101. InetInternetCloseHandle (m_hSession);
  102. m_hSession = NULL;
  103. }
  104. return m_hSession;
  105. }
  106. BOOL CAnyConnection::CloseSession ()
  107. {
  108. BOOL bRet = InetInternetCloseHandle (m_hSession);
  109. m_hSession = NULL;
  110. return bRet;
  111. }
  112. HINTERNET
  113. CAnyConnection::Connect(
  114. LPTSTR lpszServerName)
  115. {
  116. if (m_hSession) {
  117. // Ping the server if it is in the intranet to make sure that the server is online
  118. if (lpszServerName &&
  119. (_tcschr ( lpszServerName, TEXT ('.')) || Ping (lpszServerName) )) {
  120. m_hConnect = InetInternetConnect(m_hSession,
  121. lpszServerName,
  122. m_nServerPort,
  123. NULL,//m_lpszUserName,
  124. NULL, //m_lpszPassword,
  125. INTERNET_SERVICE_HTTP,
  126. 0,
  127. 0);
  128. }
  129. }
  130. return m_hConnect;
  131. }
  132. BOOL
  133. CAnyConnection::Disconnect ()
  134. {
  135. BOOL bRet = InetInternetCloseHandle (m_hConnect);
  136. m_hConnect = NULL;
  137. return bRet;
  138. }
  139. HINTERNET
  140. CAnyConnection::OpenRequest (
  141. LPTSTR lpszUrl)
  142. {
  143. HINTERNET hReq = NULL;
  144. DWORD dwFlags;
  145. if (m_hConnect) {
  146. // We need to create an Asynchronous Context for the Rest of the operations to use,
  147. // passing this in of course makes this request also asynchronous
  148. hReq = InetHttpOpenRequest(m_hConnect,
  149. g_szPOST,
  150. lpszUrl,
  151. g_szHttpVersion,
  152. NULL,
  153. NULL,
  154. INETPP_REQ_FLAGS | (m_bSecure? INTERNET_FLAG_SECURE:0),
  155. 0);
  156. }
  157. return hReq;
  158. }
  159. BOOL
  160. CAnyConnection::CloseRequest (HINTERNET hReq)
  161. {
  162. //
  163. // We have to close the handle manually, since WININET seems not to be giving us
  164. // an INTERNET_STATUS_HANDLE_CLOSING message
  165. //
  166. BOOL bSuccess;
  167. bSuccess = InetInternetCloseHandle (hReq); // When this handle is closed, the context will be closed
  168. return bSuccess;
  169. }
  170. BOOL
  171. CAnyConnection::SendRequest(
  172. HINTERNET hReq,
  173. LPCTSTR lpszHdr,
  174. DWORD cbData,
  175. LPBYTE pidi)
  176. {
  177. BOOL bRet = FALSE;
  178. CMemStream *pStream;
  179. pStream = new CMemStream (pidi, cbData);
  180. if (pStream && pStream->bValid ()){
  181. bRet = SendRequest (hReq, lpszHdr, pStream);
  182. }
  183. if (pStream) {
  184. delete pStream;
  185. }
  186. return bRet;
  187. }
  188. BOOL CAnyConnection::SendRequest(
  189. HINTERNET hReq,
  190. LPCTSTR lpszHdr,
  191. CStream *pStream)
  192. {
  193. BOOL bRet = FALSE;
  194. DWORD dwStatus;
  195. DWORD cbStatus = sizeof(dwStatus);
  196. BOOL bRetry = FALSE;
  197. DWORD dwRetryCount = 0;
  198. BOOL bShowUI = FALSE;
  199. DWORD cbData;
  200. PBYTE pBuf = NULL;
  201. DWORD cbRead;
  202. if (!pStream->GetTotalSize (&cbData))
  203. return FALSE;
  204. pBuf = new BYTE[gm_dwSendSize];
  205. if (!pBuf)
  206. return FALSE;
  207. #define MAX_RETRY 3
  208. do {
  209. BOOL bSuccess = FALSE;
  210. BOOL bLeave;
  211. if (cbData < gm_dwSendSize) {
  212. if (pStream->Reset() &&
  213. pStream->Read (pBuf, cbData, &cbRead) && cbRead == cbData) {
  214. // If what we want to send is small, we send it with HttpSendRequest and not
  215. // HttpSendRequestEx, this is to wotk around a problem where we get timeouts on
  216. // receive on very small data transactions
  217. bSuccess = InetHttpSendRequest(hReq,
  218. lpszHdr,
  219. (lpszHdr ? (DWORD)-1 : 0),
  220. pBuf,
  221. cbData);
  222. }
  223. } else {
  224. do {
  225. BOOL bSuccessSend;
  226. // The timeout value for the packets applies for an entire session, so, instead of sending in
  227. // one chuck, we have to send in smaller chunks
  228. INTERNET_BUFFERS BufferIn;
  229. bLeave = TRUE;
  230. BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
  231. BufferIn.Next = NULL;
  232. BufferIn.lpcszHeader = lpszHdr;
  233. if (lpszHdr)
  234. BufferIn.dwHeadersLength = sizeof(TCHAR)*lstrlen(lpszHdr);
  235. else
  236. BufferIn.dwHeadersLength = 0;
  237. BufferIn.dwHeadersTotal = 1; // There is one header to send
  238. BufferIn.lpvBuffer = NULL; // We defer this to the multiple write side
  239. BufferIn.dwBufferLength = 0; // The total buffer length
  240. BufferIn.dwBufferTotal = cbData; // This is the size of the data we are about to send
  241. BufferIn.dwOffsetLow = 0; // No offset into the buffers
  242. BufferIn.dwOffsetHigh = 0;
  243. // Since we will only ever be sending one request per hReq handle, we can associate
  244. // the context with all of these operations
  245. bSuccess = InetHttpSendRequestEx (hReq,
  246. &BufferIn,
  247. NULL,
  248. 0,
  249. 0);
  250. if (bSuccess) {
  251. bSuccess = pStream->Reset();
  252. }
  253. DWORD dwBufPos = 0; // This is our current point in the buffer
  254. DWORD dwRemaining = cbData; // These are the number of bytes left to send
  255. bSuccessSend = bSuccess;
  256. while (bSuccess && dwRemaining) { // While we have data to send and the operations are
  257. // successful
  258. DWORD dwWrite = min( dwRemaining, gm_dwSendSize); // The amount to write
  259. DWORD dwWritten; // The amount actually written
  260. if (pStream->Read (pBuf, dwWrite, &cbRead) && cbRead == dwWrite) {
  261. bSuccess = InetInternetWriteFile (hReq, pBuf, dwWrite, &dwWritten);
  262. if (bSuccess) {
  263. bSuccess = dwWritten ? TRUE : FALSE;
  264. dwRemaining -= dwWritten; // Remaining amount decreases by this
  265. dwBufPos += dwWritten; // Advance through the buffer
  266. if (dwWritten != dwWrite) {
  267. // We need to adjust the pointer, since not all the bytes are
  268. // successfully sent to the server
  269. //
  270. bSuccess = pStream->SetPtr (dwBufPos);
  271. }
  272. }
  273. }
  274. else
  275. bSuccess = FALSE;
  276. }
  277. BOOL bEndSuccess = FALSE;
  278. if (bSuccessSend) { // We started the request successfully, so we can end it successfully
  279. bEndSuccess = InetHttpEndRequest (hReq,
  280. NULL,
  281. 0,
  282. 0);
  283. }
  284. if (!bEndSuccess && GetLastError() == ERROR_INTERNET_FORCE_RETRY)
  285. bLeave = FALSE;
  286. bSuccess = bSuccess && bEndSuccess && bSuccessSend;
  287. } while (!bLeave);
  288. }
  289. if (bSuccess) {
  290. if ( InetHttpQueryInfo(hReq,
  291. HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
  292. &dwStatus,
  293. &cbStatus,
  294. NULL) ) {
  295. switch (dwStatus) {
  296. case HTTP_STATUS_DENIED:
  297. case HTTP_STATUS_PROXY_AUTH_REQ:
  298. SetLastError (ERROR_ACCESS_DENIED);
  299. break;
  300. case HTTP_STATUS_FORBIDDEN:
  301. SetLastError (HTTP_STATUS_FORBIDDEN);
  302. break;
  303. case HTTP_STATUS_OK:
  304. bRet = TRUE;
  305. break;
  306. case HTTP_STATUS_SERVER_ERROR:
  307. DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : HTTP_STATUS_SERVER_ERROR")));
  308. SetLastError (ERROR_INVALID_PRINTER_NAME);
  309. break;
  310. default:
  311. if ((dwStatus >= HTTP_STATUS_BAD_REQUEST) &&
  312. (dwStatus < HTTP_STATUS_SERVER_ERROR)) {
  313. SetLastError(ERROR_INVALID_PRINTER_NAME);
  314. } else {
  315. // We get some other errors, but don't know how to handle it
  316. //
  317. DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : Unknown Error (%d)"), dwStatus));
  318. SetLastError (ERROR_INVALID_HANDLE);
  319. }
  320. break;
  321. }
  322. }
  323. }
  324. else {
  325. if (m_bSecure) {
  326. DWORD dwFlags = 0;
  327. DWORD dwRet;
  328. if (m_bShowSecDlg) {
  329. bShowUI = TRUE;
  330. dwRet = InetInternetErrorDlg (GetTopWindow (NULL),
  331. hReq,
  332. GetLastError(),
  333. FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);
  334. if (dwRet == ERROR_SUCCESS || dwRet == ERROR_INTERNET_FORCE_RETRY) {
  335. bRetry = TRUE;
  336. }
  337. }
  338. else {
  339. switch (GetLastError ()) {
  340. case ERROR_INTERNET_INVALID_CA:
  341. dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
  342. break;
  343. default:
  344. // All other failure, try to ignore everything and retry
  345. dwFlags = SECURITY_FLAG_IGNORE_REVOCATION |
  346. SECURITY_FLAG_IGNORE_UNKNOWN_CA |
  347. SECURITY_FLAG_IGNORE_WRONG_USAGE |
  348. SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
  349. SECURITY_FLAG_IGNORE_CERT_DATE_INVALID|
  350. SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS |
  351. SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP ;
  352. break;
  353. }
  354. if (InetInternetSetOption(hReq,
  355. INTERNET_OPTION_SECURITY_FLAGS,
  356. &dwFlags,
  357. sizeof (DWORD))) {
  358. bRetry = TRUE;
  359. }
  360. }
  361. }
  362. }
  363. }
  364. while (bRetry && ++dwRetryCount < MAX_RETRY);
  365. if (!bRet && GetLastError () == ERROR_INTERNET_LOGIN_FAILURE)
  366. {
  367. SetLastError (ERROR_ACCESS_DENIED);
  368. }
  369. if (bShowUI) {
  370. // We only show the dialog once.
  371. m_bShowSecDlg = FALSE;
  372. }
  373. if (pBuf) {
  374. delete [] pBuf;
  375. }
  376. return bRet;
  377. }
  378. BOOL CAnyConnection::ReadFile (
  379. HINTERNET hReq,
  380. LPVOID lpvBuffer,
  381. DWORD cbBuffer,
  382. LPDWORD lpcbRd)
  383. {
  384. BOOL bSuccess;
  385. bSuccess = InetInternetReadFile(hReq, lpvBuffer, cbBuffer, lpcbRd);
  386. return bSuccess;
  387. }
  388. BOOL CAnyConnection::SetPassword (
  389. HINTERNET hReq,
  390. LPTSTR lpszUserName,
  391. LPTSTR lpszPassword)
  392. {
  393. BOOL bRet = FALSE;
  394. TCHAR szNULL[] = TEXT ("");
  395. if (!lpszUserName) {
  396. lpszUserName = szNULL;
  397. }
  398. if (!lpszPassword) {
  399. lpszPassword = szNULL;
  400. }
  401. if ( InetInternetSetOption (hReq,
  402. INTERNET_OPTION_USERNAME,
  403. lpszUserName,
  404. (DWORD) (lstrlen(lpszUserName) + 1)) &&
  405. InetInternetSetOption (hReq,
  406. INTERNET_OPTION_PASSWORD,
  407. lpszPassword,
  408. (DWORD) (lstrlen(lpszPassword) + 1)) ) {
  409. bRet = TRUE;
  410. }
  411. return bRet;
  412. }
  413. BOOL CAnyConnection::GetAuthSchem (
  414. HINTERNET hReq,
  415. LPSTR lpszScheme,
  416. DWORD dwSize)
  417. {
  418. DWORD dwIndex = 0;
  419. return InetHttpQueryInfo(hReq, HTTP_QUERY_WWW_AUTHENTICATE, (LPVOID)lpszScheme, &dwSize, &dwIndex);
  420. }
  421. void CAnyConnection::SetShowSecurityDlg (
  422. BOOL bShowSecDlg)
  423. {
  424. m_bShowSecDlg = bShowSecDlg;
  425. }