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.

1360 lines
38 KiB

  1. /*****************************************************************************\
  2. * MODULE: portmgr.cxx
  3. *
  4. * The module contains routines for handling the http port connection
  5. * for internet priting
  6. *
  7. * Copyright (C) 1996-1998 Microsoft Corporation
  8. *
  9. * History:
  10. * 22-Jul-1996 WeihaiC Created
  11. *
  12. \*****************************************************************************/
  13. #include "precomp.h"
  14. #include "priv.h"
  15. // This the length used to fetch the authentication scheme. I don't see any reason
  16. // that the authentication scheme could be longer.
  17. #define MAX_SCHEME_LEN 255
  18. CPortMgr::CPortMgr ():
  19. // Put all the private member variable here
  20. m_hSession (NULL),
  21. m_hConnect (NULL),
  22. m_lpszPassword (NULL),
  23. m_lpszUserName (NULL),
  24. m_lpszHostName (NULL),
  25. m_lpszUri (NULL),
  26. m_lpszPortName (NULL),
  27. m_bPortCreate (FALSE),
  28. m_bForceAuthSupported (TRUE), //We set it to be TRUE so that we will always try it.
  29. m_pPortSettingMgr (NULL),
  30. m_bSecure (FALSE),
  31. m_nPort (0),
  32. m_bValid (FALSE)
  33. {
  34. }
  35. CPortMgr::~CPortMgr ()
  36. {
  37. LocalFree (m_lpszPassword);
  38. LocalFree (m_lpszUserName);
  39. LocalFree (m_lpszHostName);
  40. LocalFree (m_lpszUri);
  41. LocalFree (m_lpszPortName);
  42. m_hSession = NULL;
  43. m_hConnect = NULL;
  44. }
  45. HINTERNET
  46. CPortMgr::_OpenRequest (
  47. CAnyConnection *pConnection)
  48. {
  49. HINTERNET hReq = NULL;
  50. if (pConnection && pConnection->OpenSession ()) {
  51. if (pConnection->Connect (m_lpszHostName)) {
  52. hReq = pConnection->OpenRequest (m_lpszUri);
  53. }
  54. }
  55. return hReq;
  56. }
  57. BOOL
  58. CPortMgr::_CloseRequest (
  59. CAnyConnection *pConnection,
  60. HINTERNET hReq)
  61. {
  62. BOOL bRet = FALSE;
  63. if (pConnection->CloseRequest (hReq)) {
  64. if (pConnection->Disconnect ()) {
  65. bRet = pConnection->CloseSession();
  66. }
  67. }
  68. return bRet;
  69. }
  70. /*****************************************************************************\
  71. * Function: SendRequest
  72. *
  73. * This function is to send an IPP request to an established connection
  74. *
  75. * The intension of the function is to send the request with specified
  76. * authentication instead of anonymous even if anonymous is enabled.
  77. * The alogortihm is as following
  78. * 1. If it is anonymous, just send the request and return
  79. * 2. Otherwise,
  80. * 3. If m_bForceAuthSupported, send ForceAuth to turn off anonymous, otherwise, goto 4
  81. * 3.a. Issue Force Authentication
  82. * 3.b. If the return value is 401 access denied, perform proper retry and return
  83. * 3.c. Otherwise, (We don't get 401 access denied). If we get other errors, return FALSE
  84. * 3.d. Check the IPP response of the Forth Authentication
  85. * 3.e. If the IPP response is OK, we return TRUE
  86. * 3.f. Otherwise, (Not Supported), we assume that the server does not
  87. * support Force Authentication, so we marek m_bForceAuthSupported as FALSE
  88. * and move on by returning a FALSE.
  89. *
  90. * 4. Send the real IPP request.
  91. *
  92. \*****************************************************************************/
  93. BOOL
  94. CPortMgr::_SendRequest (
  95. CAnyConnection *pConnection,
  96. HINTERNET hJobReq,
  97. CStream *pStream)
  98. {
  99. BOOL bRet = FALSE;
  100. DWORD cbData;
  101. // Generate the Http header and indicate the size
  102. // of the data we're sending.
  103. //
  104. if (pStream->GetTotalSize (&cbData) && cbData) {
  105. DWORD dwLE = ERROR_SUCCESS;
  106. DWORD dwAuthMethod = pConnection->GetAuthMethod ();
  107. // We need to force authentication if the method is NTLM or others
  108. if (m_bForceAuthSupported &&
  109. ( dwAuthMethod == AUTH_OTHER || dwAuthMethod == AUTH_NT)) {
  110. HINTERNET hReq;
  111. // Open a request and send force authentication IPP request
  112. if (hReq = pConnection->OpenRequest (m_lpszUri)) {
  113. bRet = _IppForceAuth (pConnection,
  114. hReq,
  115. m_lpszPortName,
  116. &dwAuthMethod);
  117. if (!bRet) {
  118. dwLE = GetLastError ();
  119. }
  120. pConnection->CloseRequest (hReq);
  121. }
  122. if (m_bForceAuthSupported && !bRet && dwLE == ERROR_ACCESS_DENIED) {
  123. // If forth authentication is supported but the server authentication fails, we return an error
  124. DBG_MSG(DBG_LEV_ERROR, (TEXT("CPortMgr::_SendRequest : Failed (lasterror=%d)"), dwLE));
  125. SetLastError (dwLE);
  126. return bRet;
  127. }
  128. }
  129. if (pConnection->SendRequest (hJobReq,
  130. g_szContentType,
  131. pStream)) {
  132. bRet = TRUE;
  133. }
  134. else {
  135. DBG_MSG(DBG_LEV_ERROR, (TEXT("CPortMgr::_SendRequest : pConnection->SendRequest Failed (lasterror=%d)"),
  136. GetLastError ()));
  137. }
  138. }
  139. return bRet;
  140. }
  141. BOOL
  142. CPortMgr::ReadFile (
  143. CAnyConnection *pConnection,
  144. HINTERNET hReq,
  145. LPVOID lpvBuffer,
  146. DWORD cbBuffer,
  147. LPDWORD lpcbRd)
  148. {
  149. BOOL bRet = FALSE;
  150. if (m_bValid && pConnection) {
  151. bRet = pConnection->ReadFile (hReq, lpvBuffer, cbBuffer, lpcbRd);
  152. }
  153. return bRet;
  154. }
  155. /*****************************************************************************\
  156. * _IppForceAuthRsp (Local Callback Routine)
  157. *
  158. * Retrieves a forth-authentication response from the IPP server
  159. *
  160. \*****************************************************************************/
  161. BOOL
  162. CPortMgr::_IppForceAuthRsp(
  163. CAnyConnection *pConnection,
  164. HINTERNET hReq,
  165. LPARAM lParam)
  166. {
  167. HANDLE hIpp;
  168. DWORD dwRet;
  169. DWORD cbRd;
  170. LPBYTE lpDta;
  171. DWORD cbDta;
  172. LPIPPRET_PRN lpRsp;
  173. DWORD cbRsp;
  174. BYTE bBuf[MAX_IPP_BUFFER];
  175. BOOL bRet = FALSE;
  176. if (hIpp = WebIppRcvOpen(IPP_RET_FORCEAUTH)) {
  177. while (TRUE) {
  178. cbRd = 0;
  179. if (pConnection->ReadFile (hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  180. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  181. switch (dwRet) {
  182. case WEBIPP_OK:
  183. if (!lpRsp) {
  184. SetLastError (ERROR_INVALID_DATA);
  185. }
  186. else if ((bRet = lpRsp->bRet) == TRUE)
  187. // This is from our server. We have already had the authentication
  188. // established
  189. bRet = TRUE;
  190. else
  191. SetLastError(lpRsp->dwLastError);
  192. WebIppFreeMem(lpRsp);
  193. goto EndValRsp;
  194. case WEBIPP_MOREDATA:
  195. // Need to do another read to fullfill our header-response.
  196. //
  197. break;
  198. default:
  199. DBG_MSG(DBG_LEV_ERROR, (TEXT("CPortMgr::_IppForceAuthRsp Err : Receive Data Error (dwRet=%d, LE=%d)"),
  200. dwRet, WebIppGetError(hIpp)));
  201. SetLastError(ERROR_INVALID_DATA);
  202. goto EndValRsp;
  203. }
  204. } else {
  205. goto EndValRsp;
  206. }
  207. }
  208. EndValRsp:
  209. WebIppRcvClose(hIpp);
  210. } else {
  211. SetLastError(ERROR_OUTOFMEMORY);
  212. }
  213. return bRet;
  214. }
  215. BOOL
  216. CPortMgr::_IppForceAuth (
  217. CAnyConnection *pConnection,
  218. HINTERNET hReq,
  219. LPCTSTR lpszPortName,
  220. PDWORD pdwAuthMethod)
  221. {
  222. LPIPPREQ_GETPRN pgp;
  223. REQINFO ri;
  224. DWORD dwRet;
  225. LPBYTE lpIpp;
  226. DWORD cbIpp;
  227. DWORD dwLE = ERROR_SUCCESS;
  228. BOOL bRet = FALSE;
  229. DWORD dwAuthMethod = pConnection->GetAuthMethod ();
  230. if (pgp = WebIppCreateGetPrnReq(0, lpszPortName)) {
  231. // Convert the request to IPP, and perform the
  232. // post.
  233. //
  234. ZeroMemory(&ri, sizeof(REQINFO));
  235. ri.cpReq = CP_UTF8;
  236. ri.idReq = IPP_REQ_FORCEAUTH;
  237. ri.fReq[0] = IPP_REQALL;
  238. ri.fReq[1] = IPP_REQALL;
  239. dwRet = WebIppSndData(IPP_REQ_FORCEAUTH,
  240. &ri,
  241. (LPBYTE)pgp,
  242. pgp->cbSize,
  243. &lpIpp,
  244. &cbIpp);
  245. // The request-structure has been converted
  246. // to IPP format, so it is ready to go to
  247. // the server.
  248. //
  249. //
  250. if (dwRet == WEBIPP_OK) {
  251. bRet = pConnection->SendRequest (hReq, g_szContentType, cbIpp, lpIpp);
  252. if (!bRet) {
  253. // Check if it is an access denied or some other error
  254. dwLE = GetLastError();
  255. if (dwLE == ERROR_ACCESS_DENIED && dwAuthMethod == AUTH_UNKNOWN) {
  256. CHAR szAuthScheme[MAX_SCHEME_LEN];
  257. static CHAR szNTLM[] = "NTLM";
  258. static CHAR szKerbero[] = "Kerbero";
  259. static CHAR szNegotiate[] = "Negotiate";
  260. if (pConnection->GetAuthSchem (hReq, szAuthScheme, MAX_SCHEME_LEN)) {
  261. // We've got the scheme
  262. if (! (*szAuthScheme)) {
  263. // It does not have authentication enabled, only Anonymous is supported
  264. *pdwAuthMethod = AUTH_ANONYMOUS;
  265. }
  266. if (strstr (szAuthScheme, szNTLM) ||
  267. strstr (szAuthScheme, szKerbero) ||
  268. strstr (szAuthScheme, szNegotiate)) {
  269. // We have authentication scheme that can authentication with no
  270. // popup, let's use it.
  271. *pdwAuthMethod = AUTH_NT;
  272. }
  273. else {
  274. // We have an authentications scheme, but we need to popup for username
  275. // and password
  276. *pdwAuthMethod = AUTH_OTHER;
  277. }
  278. bRet = TRUE;
  279. }
  280. }
  281. }
  282. else {
  283. // It means somehow, either the authentication is done,
  284. // or we get unsupported operation
  285. bRet = _IppForceAuthRsp(pConnection, hReq, 0L);
  286. if (!bRet) {
  287. // the response from the server does not seem to be OK, so
  288. // we mark m_bForceAuthSupported as FALSE so that we will not
  289. // send the ForceAuth request to the server again.
  290. m_bForceAuthSupported = FALSE;
  291. }
  292. if (bRet && dwAuthMethod == AUTH_UNKNOWN) {
  293. // The authentication is done, so let's use NTLM authentication
  294. *pdwAuthMethod = AUTH_NT;
  295. }
  296. // else degrade to old logic
  297. }
  298. WebIppFreeMem(lpIpp);
  299. }
  300. WebIppFreeMem(pgp);
  301. }
  302. if (dwLE == ERROR_INVALID_DATA) {
  303. dwLE = ERROR_INVALID_PRINTER_NAME;
  304. }
  305. if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS))
  306. SetLastError(dwLE);
  307. return bRet;
  308. }
  309. BOOL
  310. CPortMgr::_ForceAuth (
  311. CAnyConnection *pConnection,
  312. LPCTSTR lpszPortName,
  313. LPTSTR lpszHost,
  314. LPTSTR lpszUri,
  315. PDWORD pdwAuthMethod)
  316. {
  317. HINTERNET hReq;
  318. DWORD dwLE = ERROR_SUCCESS;
  319. BOOL bRet = FALSE;
  320. if (pConnection->OpenSession()) {
  321. if (pConnection->Connect (lpszHost)) {
  322. // Make the request.
  323. //
  324. if (hReq = pConnection->OpenRequest (lpszUri)) {
  325. // If request handle is established, then all
  326. // is OK so far.
  327. //
  328. bRet = _IppForceAuth (pConnection,
  329. hReq,
  330. lpszPortName,
  331. pdwAuthMethod);
  332. dwLE = GetLastError();
  333. pConnection->CloseRequest (hReq);
  334. }
  335. pConnection->Disconnect ();
  336. }
  337. pConnection->CloseSession ();
  338. }
  339. if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS))
  340. SetLastError(dwLE);
  341. return bRet;
  342. }
  343. /*****************************************************************************\
  344. * _IppValRsp (Local Callback Routine)
  345. *
  346. * Retrieves a get-printer-attributes response from the IPP server
  347. *
  348. \*****************************************************************************/
  349. BOOL
  350. CPortMgr::_IppValRsp(
  351. CAnyConnection *pConnection,
  352. HINTERNET hReq,
  353. LPARAM lParam)
  354. {
  355. HANDLE hIpp;
  356. DWORD dwRet;
  357. DWORD cbRd;
  358. LPBYTE lpDta;
  359. DWORD cbDta;
  360. LPIPPRET_PRN lpRsp;
  361. DWORD cbRsp;
  362. BYTE bBuf[MAX_IPP_BUFFER];
  363. BOOL bRet = FALSE;
  364. if (hIpp = WebIppRcvOpen(IPP_RET_GETPRN)) {
  365. while (TRUE) {
  366. cbRd = 0;
  367. if (pConnection->ReadFile (hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  368. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  369. switch (dwRet) {
  370. case WEBIPP_OK:
  371. if (!lpRsp) {
  372. SetLastError (ERROR_INVALID_DATA);
  373. }
  374. else if ((bRet = lpRsp->bRet) == FALSE)
  375. SetLastError(lpRsp->dwLastError);
  376. WebIppFreeMem(lpRsp);
  377. goto EndValRsp;
  378. case WEBIPP_MOREDATA:
  379. // Need to do another read to fullfill our header-response.
  380. //
  381. break;
  382. default:
  383. DBG_MSG(DBG_LEV_ERROR, (TEXT("CPortMgr::_IppValRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
  384. dwRet, WebIppGetError(hIpp)));
  385. SetLastError(ERROR_INVALID_DATA);
  386. goto EndValRsp;
  387. }
  388. } else {
  389. goto EndValRsp;
  390. }
  391. }
  392. EndValRsp:
  393. WebIppRcvClose(hIpp);
  394. } else {
  395. SetLastError(ERROR_OUTOFMEMORY);
  396. }
  397. return bRet;
  398. }
  399. BOOL
  400. CPortMgr::_IppValidate (
  401. CAnyConnection *pConnection,
  402. HINTERNET hReq,
  403. LPCTSTR lpszPortName)
  404. {
  405. LPIPPREQ_GETPRN pgp;
  406. REQINFO ri;
  407. DWORD dwRet;
  408. LPBYTE lpIpp;
  409. DWORD cbIpp;
  410. DWORD dwLE = ERROR_SUCCESS;
  411. BOOL bRet = FALSE;
  412. if (pgp = WebIppCreateGetPrnReq(0, lpszPortName)) {
  413. // Convert the request to IPP, and perform the
  414. // post.
  415. //
  416. ZeroMemory(&ri, sizeof(REQINFO));
  417. ri.cpReq = CP_UTF8;
  418. ri.idReq = IPP_REQ_GETPRN;
  419. ri.fReq[0] = IPP_REQALL;
  420. ri.fReq[1] = IPP_REQALL;
  421. dwRet = WebIppSndData(IPP_REQ_GETPRN,
  422. &ri,
  423. (LPBYTE)pgp,
  424. pgp->cbSize,
  425. &lpIpp,
  426. &cbIpp);
  427. // The request-structure has been converted
  428. // to IPP format, so it is ready to go to
  429. // the server.
  430. //
  431. //
  432. if (dwRet == WEBIPP_OK) {
  433. CMemStream *pStream = new CMemStream (lpIpp, cbIpp);
  434. if (pStream) {
  435. bRet = _SendRequest (pConnection, hReq, pStream);
  436. delete pStream;
  437. }
  438. if (bRet)
  439. bRet = _IppValRsp(pConnection, hReq, 0L);
  440. if (!bRet) {
  441. dwLE = GetLastError();
  442. }
  443. WebIppFreeMem(lpIpp);
  444. }
  445. WebIppFreeMem(pgp);
  446. }
  447. if (dwLE == ERROR_INVALID_DATA) {
  448. dwLE = ERROR_INVALID_PRINTER_NAME;
  449. }
  450. if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS))
  451. SetLastError(dwLE);
  452. return bRet;
  453. }
  454. BOOL
  455. CPortMgr::_CheckConnection (
  456. CAnyConnection *pConnection,
  457. LPCTSTR lpszPortName,
  458. LPTSTR lpszHost,
  459. LPTSTR lpszUri)
  460. {
  461. HINTERNET hReq;
  462. DWORD dwLE = ERROR_SUCCESS;
  463. BOOL bRet = FALSE;
  464. if (pConnection->OpenSession()) {
  465. if (pConnection->Connect (lpszHost)) {
  466. // Make the request.
  467. //
  468. if (hReq = pConnection->OpenRequest (lpszUri)) {
  469. // If request handle is established, then all
  470. // is OK so far.
  471. //
  472. bRet = _IppValidate (pConnection,
  473. hReq,
  474. lpszPortName);
  475. dwLE = GetLastError();
  476. pConnection->CloseRequest (hReq);
  477. }
  478. pConnection->Disconnect ();
  479. }
  480. pConnection->CloseSession ();
  481. }
  482. if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS))
  483. SetLastError(dwLE);
  484. return bRet;
  485. }
  486. BOOL
  487. CPortMgr::CheckConnection (void)
  488. {
  489. HINTERNET hReq;
  490. BOOL bRet = FALSE;
  491. DWORD dwLE = ERROR_SUCCESS;
  492. CAnyConnection *pConnection = NULL;
  493. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Enter CheckConnection")));
  494. if (m_bValid) {
  495. pConnection = _GetCurrentConnection ();
  496. if (hReq = _OpenRequest (pConnection)) {
  497. bRet = _IppValidate (pConnection,
  498. hReq,
  499. m_lpszPortName);
  500. if (!bRet) {
  501. dwLE = GetLastError();
  502. }
  503. _CloseRequest (pConnection, hReq);
  504. }
  505. if (pConnection) {
  506. delete pConnection;
  507. }
  508. if (!bRet && dwLE != ERROR_SUCCESS) {
  509. DBG_MSG(DBG_LEV_ERROR, (TEXT("CPortMgr::CheckConnection : Failed (lasterror=%d)"), dwLE));
  510. SetLastError (dwLE);
  511. }
  512. }
  513. else
  514. SetLastError (ERROR_INVALID_HANDLE);
  515. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Leave CheckConnection ret=%d, lasterror=%d"), bRet, GetLastError ()));
  516. return bRet;
  517. }
  518. /*****************************************************************************\
  519. * Function: Create
  520. *
  521. * This function is to establish the network connection with the given port name
  522. *
  523. * The intension of the function is to establish a network connection with
  524. * authentication instead of anonymous. The alogortihm is as following
  525. * 1. Try Anonymous
  526. * 2. If anonymous connection is NOT possible, go to step 5
  527. * 3. Try Force Authentication (Call _ForceAuth)
  528. * 3.a. Issue Force Authentication
  529. * 3.b. If the return value is 401 access denied, we start to check the
  530. * authentication scheme, otherwise, mark m_dwAuthMethod
  531. * as AUTH_ANONYMOUS and return TRUE
  532. * 3.c. If either NTLM, Kerbero or Negotiate is in the scheme, we mark
  533. * m_dwAuthMethod as AUTH_NT
  534. * Otherwise, we mark it as AUTH_OTHER
  535. * return TRUE
  536. * 3.d. (We don't get 401 access denied). If we get other errors, return FALSE
  537. * 3.e. Check the IPP response of the Forth Authentication
  538. * 3.f. If the IPP response is OK, we know we have established authentication
  539. * (This should not happen in the first time, but will happen afterward)
  540. * but we will mark m_dwAuthMethod as AUTH_NT anyway and return TRUE.
  541. * 3.g. Otherwise, (Not Supported), we assume that the server does not
  542. * support Force Authentication, so we move on by returning a FALSE.
  543. *
  544. * 4. If it returns OK, we start to use the authentication method indicated
  545. * in m_dwAuthMethod
  546. * 5. Try NTLM or other no-popup authentication
  547. * 6. Try Other popup authentications
  548. *
  549. * If the connection is established, the function returns TRUE.
  550. *
  551. \*****************************************************************************/
  552. BOOL
  553. CPortMgr::Create (
  554. LPCTSTR lpszPortName)
  555. {
  556. LPTSTR lpszHost = NULL;
  557. LPTSTR lpszShare = NULL;
  558. INTERNET_PORT nPort;
  559. CAnyConnection *pConnection = NULL;
  560. BOOL bRet = FALSE;
  561. DWORD dwLE = 0;
  562. BOOL bDone;
  563. BOOL bSecure;
  564. BOOL bAnonymous = FALSE;
  565. DWORD dwAuthMethod;
  566. // Try to find out if the server can be accessed without going
  567. // through Proxy Server
  568. //
  569. if ( utlParseHostShare(lpszPortName,
  570. &lpszHost,
  571. &lpszShare,
  572. &nPort,
  573. &bSecure)) {
  574. bDone = ! (AssignString (m_lpszHostName, lpszHost) &&
  575. AssignString (m_lpszUri, lpszShare) &&
  576. AssignString (m_lpszPortName, lpszPortName));
  577. m_bSecure = bSecure;
  578. m_nPort = nPort;
  579. // Set the flag to indicate it is creation time.
  580. //
  581. m_bPortCreate = TRUE;
  582. // Try connect and the get the proxy
  583. if (!bDone) {
  584. // We don't care about if the reset succeeded or not
  585. EndBrowserSession ();
  586. }
  587. // Try anonymous with/without proxy
  588. if (!bDone && (pConnection = new CAnonymousConnection (bSecure, nPort, FALSE))
  589. && pConnection->IsValid ()) {
  590. bDone = TRUE;
  591. if (_CheckConnection(pConnection, lpszPortName, lpszHost, lpszShare)) {
  592. bAnonymous = TRUE;
  593. }
  594. else {
  595. dwLE = GetLastError ();
  596. if (dwLE == ERROR_INTERNET_NAME_NOT_RESOLVED) {
  597. // The server name is wrong, reset tht last error
  598. // to invalid printer name
  599. //
  600. SetLastError (ERROR_INVALID_PRINTER_NAME);
  601. }
  602. else if (dwLE == HTTP_STATUS_FORBIDDEN) {
  603. SetLastError (ERROR_ACCESS_DENIED);
  604. }
  605. else if (dwLE != ERROR_INVALID_PRINTER_NAME)
  606. bDone = FALSE; // Cont to the next mode
  607. }
  608. if (bAnonymous) {
  609. // We've got an anonymous authentication
  610. if (_ForceAuth(pConnection, lpszPortName, lpszHost, lpszShare, &dwAuthMethod)) {
  611. // We've got an authentication method
  612. if (dwAuthMethod != AUTH_ANONYMOUS) {
  613. bDone = FALSE;
  614. SetLastError (ERROR_ACCESS_DENIED);
  615. if (dwAuthMethod == AUTH_OTHER) {
  616. bDone = TRUE;
  617. //weihaic goto TryOther;
  618. }
  619. }
  620. else
  621. bRet = TRUE;
  622. }
  623. else {
  624. // We've got anonymous, and the serve does not support FORCE_AUTH
  625. // so let us use it.
  626. dwAuthMethod = AUTH_ANONYMOUS;
  627. bRet = TRUE;
  628. }
  629. }
  630. }
  631. // You must have got access denied in this case
  632. // Let's try again without any password, it will work if the server has NTLM/Kerbero enabled.
  633. //
  634. if (!bDone && GetLastError () == ERROR_ACCESS_DENIED) {
  635. if (pConnection) {
  636. delete (pConnection);
  637. pConnection = NULL;
  638. }
  639. bDone = TRUE;
  640. if ( (pConnection = new CNTConnection (bSecure, nPort, FALSE) )
  641. && pConnection->IsValid ()) {
  642. if (_CheckConnection(pConnection, lpszPortName, lpszHost, lpszShare)) {
  643. dwAuthMethod = AUTH_NT;
  644. bRet = TRUE;
  645. }
  646. else {
  647. dwLE = GetLastError ();
  648. if (dwLE != ERROR_INVALID_PRINTER_NAME)
  649. bDone = FALSE; // Cont to the next mode
  650. }
  651. }
  652. }
  653. if (!bDone && GetLastError () == ERROR_ACCESS_DENIED && bAnonymous) {
  654. // We know that anonymous is enabled, so let us degrade the connection to anonymous
  655. if (pConnection) {
  656. delete (pConnection);
  657. pConnection = NULL;
  658. }
  659. // We must reset m_dwAuthMethod since when we try other authentication
  660. // m_dwAuthMethod is set to AUTH_OTHER, if we do not reset the value
  661. // when we try to send request to the server, it will fail with access
  662. // denied.
  663. //
  664. dwAuthMethod = AUTH_UNKNOWN;
  665. if (!bDone && (pConnection = new CAnonymousConnection (bSecure, nPort, FALSE))
  666. && pConnection->IsValid ()) {
  667. bDone = TRUE;
  668. if (_CheckConnection(pConnection, lpszPortName, lpszHost, lpszShare)) {
  669. bRet = TRUE;
  670. dwAuthMethod = AUTH_ANONYMOUS;
  671. }
  672. }
  673. }
  674. }
  675. // Exit point
  676. //
  677. // We need to create the port at first if we get access denied
  678. // then users can configure the port using a different user name
  679. // and password
  680. //
  681. if (!bRet && GetLastError () == ERROR_ACCESS_DENIED) {
  682. //
  683. // Force anonymous connection. This will fail anyway.
  684. //
  685. dwAuthMethod = AUTH_ACCESS_DENIED;
  686. bRet = TRUE;
  687. }
  688. if (bRet) {
  689. m_bValid = TRUE;
  690. m_pPortSettingMgr = new CPortConfigDataMgr (lpszPortName);
  691. if (m_pPortSettingMgr && m_pPortSettingMgr->bValid ()) {
  692. CPortConfigData ConfigData;
  693. ConfigData.SetAuthMethod (dwAuthMethod);
  694. bRet = m_pPortSettingMgr->SetPerPortSettings (ConfigData);
  695. }
  696. else
  697. bRet = FALSE;
  698. }
  699. if (lpszHost) {
  700. memFreeStr (lpszHost);
  701. }
  702. if (lpszShare) {
  703. memFreeStr (lpszShare);
  704. }
  705. if (!bRet) {
  706. // Clean up the connection class
  707. if (pConnection) {
  708. delete (pConnection);
  709. pConnection = NULL;
  710. }
  711. if (GetLastError () != ERROR_ACCESS_DENIED) {
  712. // Invalid Printer Name
  713. // The NT router expects inetpp to returen ERROR_INVALID_NAME,
  714. // if we return ERROR_INVALID_PRINTER_NAME, the router will return
  715. // this error back to the user
  716. //
  717. SetLastError (ERROR_INVALID_NAME);
  718. }
  719. }
  720. m_bPortCreate = FALSE;
  721. return bRet;
  722. }
  723. BOOL
  724. CPortMgr::ConfigurePort (
  725. PINET_XCV_CONFIGURATION pXcvConfigurePortReqData,
  726. PINET_CONFIGUREPORT_RESPDATA pXcvAddPortRespData,
  727. DWORD cbSize,
  728. PDWORD cbSizeNeeded)
  729. {
  730. LPTSTR lpszHost = NULL;
  731. LPTSTR lpszShare = NULL;
  732. INTERNET_PORT nPort;
  733. CAnyConnection *pConnection = NULL;
  734. BOOL bRet = FALSE;
  735. DWORD dwLE = 0;
  736. BOOL bDone;
  737. BOOL bSecure;
  738. BOOL bAnonymous = FALSE;
  739. CPortConfigData OldConfigData;
  740. LPCTSTR pPassword = NULL;
  741. // Reset everything
  742. EndBrowserSession ();
  743. //
  744. // We must retry force authentication when configuration changes
  745. //
  746. m_bForceAuthSupported = TRUE;
  747. BOOL bIgnoreSecurityDlg = pXcvConfigurePortReqData->bIgnoreSecurityDlg;
  748. DWORD dwAuthMethod = pXcvConfigurePortReqData->dwAuthMethod;
  749. switch (dwAuthMethod) {
  750. case AUTH_ANONYMOUS:
  751. pConnection = new CAnonymousConnection (m_bSecure, m_nPort, bIgnoreSecurityDlg);
  752. break;
  753. case AUTH_NT:
  754. pConnection = new CNTConnection (m_bSecure, m_nPort, bIgnoreSecurityDlg);
  755. break;
  756. case AUTH_OTHER:
  757. if (m_pPortSettingMgr->GetCurrentSettings (&OldConfigData))
  758. pPassword = OldConfigData.GetPassword();
  759. pPassword = (pXcvConfigurePortReqData->bPasswordChanged)?pXcvConfigurePortReqData->szPassword:pPassword;
  760. pConnection = new COtherConnection (m_bSecure, m_nPort,
  761. pXcvConfigurePortReqData->szUserName,
  762. pPassword,
  763. bIgnoreSecurityDlg);
  764. default:
  765. break;
  766. }
  767. if (pConnection && pConnection->IsValid()) {
  768. if (_CheckConnection(pConnection, m_lpszPortName, m_lpszHostName, m_lpszUri)) {
  769. bRet = TRUE;
  770. }
  771. else {
  772. dwLE = GetLastError ();
  773. if (dwLE == ERROR_INTERNET_NAME_NOT_RESOLVED) {
  774. // The server name is wrong, reset tht last error
  775. // to invalid printer name
  776. //
  777. SetLastError (ERROR_INVALID_PRINTER_NAME);
  778. }
  779. else if (dwLE == HTTP_STATUS_FORBIDDEN) {
  780. SetLastError (ERROR_ACCESS_DENIED);
  781. }
  782. else if (dwLE != ERROR_INVALID_PRINTER_NAME)
  783. SetLastError (dwLE);
  784. }
  785. }
  786. // Exit point
  787. if (bRet) {
  788. m_bValid = TRUE;
  789. CPortConfigData ConfigData;
  790. bRet = ConfigData.SetAuthMethod (dwAuthMethod);
  791. if (bRet) {
  792. if (dwAuthMethod == AUTH_OTHER) {
  793. bRet = ConfigData.SetUserName (pXcvConfigurePortReqData->szUserName) &&
  794. ConfigData.SetPassword (pPassword);
  795. }
  796. else
  797. bRet = ConfigData.SetUserName(NULL) && ConfigData.SetPassword(NULL);
  798. if (bRet) {
  799. bRet = m_pPortSettingMgr->SetPerUserSettings (ConfigData);
  800. }
  801. if (bRet && pXcvConfigurePortReqData->bSettingForAll)
  802. bRet = m_pPortSettingMgr->SetPerPortSettings (ConfigData);
  803. }
  804. }
  805. return bRet;
  806. }
  807. BOOL
  808. CPortMgr::GetCurrentConfiguration (
  809. PINET_XCV_CONFIGURATION pXcvConfiguration)
  810. {
  811. CPortConfigData ConfigData;
  812. ZeroMemory (pXcvConfiguration, sizeof (INET_XCV_CONFIGURATION));
  813. m_pPortSettingMgr->GetCurrentSettings (&ConfigData);
  814. pXcvConfiguration->dwVersion = 1;
  815. pXcvConfiguration->dwAuthMethod = ConfigData.GetAuthMethod ();
  816. if (pXcvConfiguration->dwAuthMethod == AUTH_OTHER) {
  817. if (ConfigData.GetUserName()) {
  818. StringCchCopy(pXcvConfiguration->szUserName, COUNTOF(pXcvConfiguration->szUserName), ConfigData.GetUserName());
  819. }
  820. }
  821. pXcvConfiguration->bIgnoreSecurityDlg = ConfigData.GetIgnoreSecurityDlg();
  822. return TRUE;
  823. }
  824. BOOL
  825. CPortMgr::Init (
  826. LPCTSTR lpszPortName)
  827. {
  828. LPTSTR lpszHost = NULL;
  829. LPTSTR lpszShare = NULL;
  830. INTERNET_PORT nPort;
  831. BOOL bRet = FALSE;
  832. BOOL bSecure = FALSE;
  833. if ( utlParseHostShare(lpszPortName,
  834. &lpszHost,
  835. &lpszShare,
  836. &nPort,
  837. &bSecure)) {
  838. m_pPortSettingMgr = new CPortConfigDataMgr (lpszPortName);
  839. if (m_pPortSettingMgr && m_pPortSettingMgr->bValid ()) {
  840. bRet = TRUE;
  841. }
  842. }
  843. if (bRet) {
  844. m_bValid = TRUE;
  845. m_bSecure = bSecure;
  846. m_nPort = nPort;
  847. bRet = AssignString (m_lpszHostName, lpszHost) &&
  848. AssignString (m_lpszUri, lpszShare) &&
  849. AssignString (m_lpszPortName, lpszPortName);
  850. }
  851. if (lpszHost) {
  852. memFreeStr (lpszHost);
  853. }
  854. if (lpszShare) {
  855. memFreeStr (lpszShare);
  856. }
  857. return bRet;
  858. }
  859. BOOL
  860. CPortMgr::Remove (void)
  861. {
  862. if (m_pPortSettingMgr) {
  863. m_pPortSettingMgr->DeleteAllSettings ();
  864. }
  865. return TRUE;
  866. }
  867. CAnyConnection *
  868. CPortMgr::_GetCurrentConnection ()
  869. {
  870. CPortConfigData ConfigData;
  871. CAnyConnection *pConnection = NULL;
  872. if (m_pPortSettingMgr->GetCurrentSettings (&ConfigData)) {
  873. switch (ConfigData.GetAuthMethod ()) {
  874. case AUTH_ANONYMOUS:
  875. pConnection = new CAnonymousConnection (m_bSecure, m_nPort, ConfigData.GetIgnoreSecurityDlg());
  876. break;
  877. case AUTH_NT:
  878. pConnection = new CNTConnection (m_bSecure, m_nPort, ConfigData.GetIgnoreSecurityDlg());
  879. break;
  880. case AUTH_OTHER:
  881. pConnection = new COtherConnection (m_bSecure, m_nPort,
  882. ConfigData.GetUserName(), ConfigData.GetPassword(),
  883. ConfigData.GetIgnoreSecurityDlg());
  884. break;
  885. case AUTH_ACCESS_DENIED:
  886. SetLastError (ERROR_ACCESS_DENIED);
  887. break;
  888. default:
  889. SetLastError (ERROR_INVALID_HANDLE);
  890. break;
  891. }
  892. }
  893. else {
  894. DBG_MSG(DBG_LEV_ERROR, (TEXT("_GetCurrentConnection - Err GetCurrentSettings failed (LE=%d)"), GetLastError ()));
  895. SetLastError (ERROR_INVALID_HANDLE);
  896. }
  897. return pConnection;
  898. }
  899. BOOL
  900. CPortMgr::SendRequest(
  901. PCINETMONPORT pIniPort,
  902. LPBYTE lpIpp,
  903. DWORD cbIpp,
  904. IPPRSPPROC pfnRsp,
  905. LPARAM lParam)
  906. {
  907. BOOL bRet = FALSE;
  908. CMemStream *pStream;
  909. pStream = new CMemStream (lpIpp, cbIpp);
  910. if (pStream && pStream->bValid ()){
  911. bRet = SendRequest (pIniPort, pStream, pfnRsp, lParam);
  912. }
  913. if (pStream) {
  914. delete pStream;
  915. }
  916. return bRet;
  917. }
  918. BOOL
  919. CPortMgr::SendRequest(
  920. PCINETMONPORT pIniPort,
  921. CStream *pStream,
  922. IPPRSPPROC pfnRsp,
  923. LPARAM lParam)
  924. {
  925. HINTERNET hReq;
  926. DWORD dwLE = ERROR_SUCCESS;
  927. BOOL bRet = FALSE;
  928. if (m_bValid) {
  929. CAnyConnection * pConnection;
  930. pConnection = _GetCurrentConnection ();
  931. if (pConnection) {
  932. hReq = _OpenRequest (pConnection);
  933. // If succeeded, then build the content-length-header.
  934. //
  935. if (hReq) {
  936. bRet = _SendRequest (pConnection, hReq, pStream);
  937. if (bRet)
  938. bRet = (pfnRsp ? (*pfnRsp)(pConnection, hReq, pIniPort, lParam) : TRUE);
  939. dwLE = GetLastError();
  940. _CloseRequest (pConnection, hReq);
  941. }
  942. }
  943. else
  944. dwLE = GetLastError ();
  945. if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS)) {
  946. if (dwLE == HTTP_STATUS_FORBIDDEN) {
  947. SetLastError (ERROR_ACCESS_DENIED);
  948. }
  949. else
  950. SetLastError(dwLE);
  951. }
  952. }
  953. else {
  954. SetLastError (ERROR_INVALID_HANDLE);
  955. }
  956. return bRet;
  957. }
  958. DWORD
  959. CPortMgr::IncreaseUserRefCount(
  960. CLogonUserData *pUser)
  961. /*++
  962. Routine Description:
  963. Increase the Ref Count for the current user in the Port Manager.
  964. Arguments:
  965. pUser - The user that we want to increment the RefCount for.
  966. Return Value:
  967. The current refcount for the user, or MAXDWORD if the user could not be found.
  968. --*/
  969. {
  970. CLogonUserData *pPortUser = NULL;
  971. CLogonUserData *pNewUser = NULL;
  972. DWORD dwRefCount = MAXDWORD;
  973. DBG_ASSERT( pUser , (TEXT("CPortMgr::IncreaseUserRefCount - pUser is NULL.")) );
  974. DBG_ASSERT( pUser->bValid(), (TEXT("CPortMgr::IncreaseUserRefCount - pUser is invalid.")) );
  975. m_UserList.Lock(); // We need to be sure only one CurUser is considered per port per time.
  976. if (pPortUser = m_UserList.Find( pUser )) {
  977. // We have found the port user, increment their refcount.
  978. dwRefCount = pPortUser->IncRefCount();
  979. DBG_MSG(DBG_LEV_INFO,
  980. (TEXT("Info: IncRef to (%d), User (%p)"), dwRefCount, pPortUser ) );
  981. } else {
  982. pNewUser = new CLogonUserData; // A new user automatically has a ref-count of 1.
  983. if (pNewUser != NULL) {
  984. *pNewUser = *pUser; // Assign data across
  985. if (!pNewUser->bValid() ||
  986. !m_UserList.Insert( pNewUser )) {
  987. delete pNewUser;
  988. pNewUser = NULL;
  989. SetLastError( ERROR_INVALID_PARAMETER );
  990. } else
  991. dwRefCount = 1;
  992. }
  993. }
  994. m_UserList.Unlock();
  995. return dwRefCount;
  996. }
  997. CLogonUserData*
  998. CPortMgr::GetUserIfLastDecRef(
  999. CLogonUserData *pUser)
  1000. /*++
  1001. Routine Description:
  1002. This routine finds the reference count for the current user. If the reference count is
  1003. zero we return a pointer to the user, otherwise we return NULL. This will be used by
  1004. the Cache Manager to invalid the cache for the particular user.
  1005. NOTE: Caller must Free the pUser.
  1006. Arguments:
  1007. None
  1008. Return Value:
  1009. A pointer to the user if their RefCount has gone to Zero, NULL otherwise.
  1010. --*/
  1011. {
  1012. CLogonUserData *pPortUser = NULL;
  1013. CLogonUserData *pNewUser = NULL;
  1014. DWORD dwRefCount;
  1015. DBG_ASSERT( pUser , (TEXT("CPortMgr::GetUserIfLastDecRef - pUser is NULL.")) );
  1016. DBG_ASSERT( pUser->bValid(), (TEXT("CPortMgr::GetUserIfLastDecRef - pUser is invalid.")) );
  1017. m_UserList.Lock();
  1018. if (pPortUser = m_UserList.Find( pUser )) {
  1019. // We have found the port user, increment their refcount.
  1020. // Make sure that two threads aren't handling the RefCount at the same
  1021. // time
  1022. dwRefCount = pPortUser->DecRefCount();
  1023. DBG_MSG(DBG_LEV_INFO,
  1024. (TEXT("Info: DecRef to (%d), User (%p)"), dwRefCount, pPortUser ) );
  1025. if (dwRefCount == 0) {
  1026. pNewUser = new CLogonUserData;
  1027. if (pNewUser != NULL) {
  1028. *pNewUser = *pPortUser;
  1029. }
  1030. m_UserList.Delete( pPortUser ); // We don't need him in the list anymore
  1031. }
  1032. }
  1033. m_UserList.Unlock();
  1034. return pNewUser;
  1035. }