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.

1489 lines
42 KiB

  1. #include "stdafx.h"
  2. #include "rcbdyctl.h"
  3. #include "IMSession.h"
  4. #include "wincrypt.h"
  5. #include "auth.h"
  6. #include "assert.h"
  7. #include "wininet.h"
  8. #include "msgrua.h"
  9. #include "msgrua_i.c"
  10. #include "utils.h"
  11. #include "lock_i.c"
  12. #include "sessions.h"
  13. #include "sessions_i.c"
  14. #include "helpservicetypelib.h"
  15. #include "helpservicetypelib_i.c"
  16. #include "safrcfiledlg.h"
  17. #include "safrcfiledlg_i.c"
  18. /////////////////////////////////////////////////////////////////////////
  19. // CIMSession
  20. // Global help functions declaration.
  21. HWND InitInstance(HINSTANCE hInstance, int nCmdShow);
  22. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  23. DWORD WINAPI HSCInviteThread(LPVOID lpParam);
  24. HRESULT UnlockSession(CIMSession* pThis);
  25. VOID CALLBACK ConnectToExpertCallback(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime);
  26. UINT_PTR g_timerID;
  27. CIMSession * g_pThis;
  28. HWND g_StatusDlg = NULL;
  29. // Window class name
  30. TCHAR szWindowClass[] = TEXT("Microsoft Remote Assistance Messenger UNLOCK window");
  31. extern HINSTANCE g_hInstance;
  32. #define VIESDESKTOP_PERMISSION_NOT_REQUIRE 0x4
  33. #define SESSION_EXPIRY 305
  34. #define RA_TIMER_UNLOCK_ID 0x1
  35. #define RA_TIMEOUT_UNLOCK 180 * 1000 // 3 minutes.
  36. #define RA_TIMEOUT_USER 1800 * 1000 // 30 minutes
  37. HANDLE g_hLockEvent = NULL;
  38. BOOL g_bActionCancel = FALSE;
  39. HWND g_hWnd = NULL;
  40. LPSTREAM g_spInvitee = NULL;
  41. LPSTREAM g_spStatus = NULL;
  42. CIMSession::CIMSession()
  43. {
  44. m_pSessObj = NULL;
  45. m_pSessMgr = NULL;
  46. m_pMsgrLockKey = NULL;
  47. m_bIsInviter = TRUE;
  48. m_hCryptProv = NULL;
  49. m_hPublicKey = NULL;
  50. m_pSessionEvent = NULL;
  51. m_iState = 0;
  52. m_pfnSessionStatus = NULL;
  53. m_pSessionMgrEvent = NULL;
  54. m_bIsHSC = FALSE;
  55. m_pInvitee = NULL;
  56. m_bLocked = TRUE;
  57. m_bExchangeUser = FALSE;
  58. }
  59. CIMSession::~CIMSession()
  60. {
  61. if (m_pSessObj)
  62. {
  63. if (m_pSessionEvent)
  64. m_pSessionEvent->DispEventUnadvise(m_pSessObj);
  65. m_pSessObj->Release();
  66. }
  67. if (m_pSessionMgrEvent)
  68. m_pSessionMgrEvent->Release();
  69. if (m_pSessionEvent)
  70. m_pSessionEvent->Release();
  71. if (m_pMsgrLockKey)
  72. m_pMsgrLockKey->Release();
  73. if (m_pSessMgr)
  74. m_pSessMgr->Release();
  75. if (m_hPublicKey)
  76. CryptDestroyKey(m_hPublicKey);
  77. if (m_hCryptProv)
  78. CryptReleaseContext(m_hCryptProv, 0);
  79. }
  80. STDMETHODIMP CIMSession::put_OnSessionStatus(IDispatch* pfn)
  81. {
  82. m_pfnSessionStatus = pfn;
  83. return S_OK;
  84. }
  85. STDMETHODIMP CIMSession::get_ReceivedUserTicket(BSTR* pSalemTicket)
  86. {
  87. if (pSalemTicket == NULL)
  88. return E_INVALIDARG;
  89. *pSalemTicket = m_bstrSalemTicket.Copy();
  90. return S_OK;
  91. }
  92. STDMETHODIMP CIMSession::Hook(IMsgrSession*, HWND hWnd)
  93. {
  94. HRESULT hr = S_OK;
  95. m_hWnd = hWnd;
  96. return hr;
  97. }
  98. STDMETHODIMP CIMSession::ContextDataProperty(BSTR pName, BSTR* ppValue)
  99. {
  100. HRESULT hr = S_OK;
  101. CComPtr<IRASetting> cpSetting;
  102. if (*ppValue != NULL)
  103. {
  104. SysFreeString(*ppValue);
  105. *ppValue = NULL;
  106. }
  107. if (m_bstrContextData.Length() == 0)
  108. goto done;
  109. if (pName == NULL || *pName == L'\0')
  110. {
  111. *ppValue = m_bstrContextData.Copy();
  112. goto done;
  113. }
  114. hr = cpSetting.CoCreateInstance( CLSID_RASetting, NULL, CLSCTX_INPROC_SERVER);
  115. if (FAILED_HR(_T("ISetting->CoCreateInstance failed: %s"), hr))
  116. goto done;
  117. cpSetting->get_GetPropertyInBlob(m_bstrContextData, pName, ppValue);
  118. done:
  119. return hr;
  120. }
  121. STDMETHODIMP CIMSession::get_User(IDispatch** ppUser)
  122. {
  123. HRESULT hr = S_OK;
  124. if (ppUser == NULL)
  125. {
  126. hr = E_INVALIDARG;
  127. goto done;
  128. }
  129. if (m_pSessObj)
  130. {
  131. hr = m_pSessObj->get_User(ppUser);
  132. if (FAILED_HR(_T("get_User failed %s"), hr))
  133. goto done;
  134. }
  135. else
  136. {
  137. DEBUG_MSG(_T("No Session found"));
  138. hr = S_OK;
  139. *ppUser = NULL;
  140. }
  141. done:
  142. return hr;
  143. }
  144. STDMETHODIMP CIMSession::get_IsInviter(BOOL* pVal)
  145. {
  146. if (pVal == NULL)
  147. return E_INVALIDARG;
  148. *pVal = m_bIsInviter;
  149. return S_OK;
  150. }
  151. STDMETHODIMP CIMSession::CloseRA()
  152. {
  153. HRESULT hr = S_OK;
  154. if(m_bIsInviter && m_hWnd) // for inviter, this is the last function to call.
  155. SendMessage(m_hWnd, WM_CLOSE, NULL, NULL);
  156. return hr;
  157. }
  158. HRESULT CIMSession::GenEncryptdNoviceBlob(BSTR pPublicKeyBlob, BSTR pSalemTicket, BSTR* pBlob)
  159. {
  160. TraceSpew(_T("Funct: GenEncryptedNoviceBlob"));
  161. HRESULT hr;
  162. if (!pPublicKeyBlob)
  163. return FALSE;
  164. DWORD dwLen, dwBlobLen, dwSessionKeyCount, dwSalemCount;
  165. LPBYTE pBuf =NULL;
  166. HCRYPTKEY hSessKey =NULL;
  167. HCRYPTKEY hPublicKey =NULL;
  168. BSTR pSessionKeyBlob =NULL;
  169. BSTR pSalemBlob =NULL;
  170. TCHAR szHeader[20];
  171. CComBSTR bstrBlob;
  172. if (FAILED(hr = InitCSP(FALSE)))
  173. goto done;
  174. // Import public key
  175. if (FAILED(hr = StringToBinary(pPublicKeyBlob, wcslen(pPublicKeyBlob), &pBuf, &dwLen)))
  176. goto done;
  177. if (!CryptImportKey(m_hCryptProv,
  178. pBuf,
  179. (UINT)dwLen,
  180. 0,
  181. 0,
  182. &hPublicKey))
  183. {
  184. DEBUG_MSG(_T("Can't import public key"));
  185. hr = HRESULT_FROM_WIN32(GetLastError());
  186. goto done;
  187. }
  188. // Gen session key.
  189. if (!CryptGenKey(m_hCryptProv, CALG_RC2, CRYPT_EXPORTABLE, &hSessKey))
  190. {
  191. DEBUG_MSG(_T("Create Session key failed"));
  192. hr = HRESULT_FROM_WIN32(GetLastError());
  193. goto done;
  194. }
  195. DWORD dwBitLength = 40;
  196. if (!CryptSetKeyParam(hSessKey, KP_EFFECTIVE_KEYLEN, (PBYTE) &dwBitLength, 0))
  197. {
  198. DEBUG_MSG(_T("Set KEYLEN failed"));
  199. hr = HRESULT_FROM_WIN32(GetLastError());
  200. goto done;
  201. }
  202. if (FAILED(hr=GetKeyExportString(hSessKey, hPublicKey, SIMPLEBLOB, &pSessionKeyBlob, &dwSessionKeyCount)))
  203. goto done;
  204. // Encrypt SalemTicket
  205. dwBlobLen = dwLen = wcslen(pSalemTicket) * sizeof(OLECHAR);
  206. if (!CryptEncrypt(hSessKey, NULL, TRUE, 0, NULL, &dwBlobLen, dwLen))
  207. {
  208. DEBUG_MSG(_T("Can't calculate salem ticket buffer length."));
  209. hr = HRESULT_FROM_WIN32(GetLastError());
  210. goto done;
  211. }
  212. if (pBuf)
  213. free(pBuf);
  214. if((pBuf = (LPBYTE)malloc(dwBlobLen)) == NULL)
  215. {
  216. hr = E_OUTOFMEMORY;
  217. goto done;
  218. }
  219. ZeroMemory(pBuf, dwBlobLen);
  220. memcpy(pBuf, (LPBYTE)pSalemTicket, dwLen);
  221. if (!CryptEncrypt(hSessKey, NULL, TRUE, 0, pBuf, &dwLen, dwBlobLen))
  222. {
  223. DEBUG_MSG(_T("Can't calculate user ticket length"));
  224. hr = HRESULT_FROM_WIN32(GetLastError());
  225. goto done;
  226. }
  227. // Need to generate salem ticket blob
  228. if (FAILED(hr=BinaryToString(pBuf, dwBlobLen, &pSalemBlob, &dwSalemCount)))
  229. goto done;
  230. // Generate final Blob
  231. wsprintf(szHeader, _T("%d;S="), dwSessionKeyCount + 2);
  232. bstrBlob = szHeader;
  233. bstrBlob.AppendBSTR(pSessionKeyBlob);
  234. wsprintf(szHeader, _T("%d;U="), dwSalemCount + 2);
  235. bstrBlob.Append(szHeader);
  236. bstrBlob.AppendBSTR(pSalemBlob);
  237. if (!InternetGetConnectedState(&dwLen, 0))
  238. {
  239. DEBUG_MSG(_T("No Internet connection"));
  240. }
  241. else
  242. {
  243. if (dwLen & INTERNET_CONNECTION_MODEM) // connected through Modem
  244. {
  245. bstrBlob.Append("3;L=1");
  246. }
  247. }
  248. *pBlob = bstrBlob.Detach();
  249. done:
  250. if (pBuf)
  251. free(pBuf);
  252. if (pSessionKeyBlob)
  253. SysFreeString(pSessionKeyBlob);
  254. if (pSalemBlob)
  255. SysFreeString(pSalemBlob);
  256. if (hPublicKey)
  257. CryptDestroyKey(hPublicKey);
  258. if (hSessKey)
  259. CryptDestroyKey(hSessKey);
  260. return hr;
  261. }
  262. HRESULT CIMSession::InviterSendSalemTicket(BSTR pContext)
  263. {
  264. TraceSpew(_T("Funct: InviterSendSalemTicket"));
  265. HRESULT hr;
  266. CComPtr<IRASetting> cpSetting;
  267. ISAFRemoteDesktopSession *pRCS = NULL;
  268. BSTR pPublicKeyBlob = NULL;
  269. CComBSTR bstrExpertTicket;
  270. CComBSTR bstrSalemTicket;
  271. CComBSTR bstrBlob, bstrExpertName, bstrUserBlob;
  272. CComPtr<IClassFactory> fact;
  273. CComQIPtr<IPCHUtility> disp;
  274. CComPtr<IDispatch> cpDisp;
  275. CComPtr<IMessengerContact> cpExpert;
  276. TCHAR szHeader[100];
  277. hr = cpSetting.CoCreateInstance( CLSID_RASetting, NULL, CLSCTX_INPROC_SERVER);
  278. if (FAILED_HR(_T("ISetting->CoCreateInstance failed: %s"), hr))
  279. goto done;
  280. // bstrExpertBlob has 2 part: Expert ticket and expert public key. Names: "ET" and "PK"
  281. cpSetting->get_GetPropertyInBlob(pContext, CComBSTR("ET"), &m_bstrExpertTicket);
  282. if (m_bstrExpertTicket.Length() == 0)
  283. {
  284. DEBUG_MSG(_T("No expert ticket"));
  285. goto done;
  286. }
  287. cpSetting->get_GetPropertyInBlob(pContext, CComBSTR("PK"), &pPublicKeyBlob);
  288. // Generate SALEM Ticket.
  289. hr =::CoGetClassObject(CLSID_PCHService, CLSCTX_ALL, NULL, IID_IClassFactory, (void**)&fact );
  290. if (FAILED_HR(_T("CoGetClassObject failed: %s"), hr))
  291. goto done;
  292. // Get Expert name and put it into userblob
  293. hr = m_pSessObj->get_User(&cpDisp);
  294. if (FAILED_HR(_T("get_User failed %s"), hr))
  295. goto done;
  296. hr = cpDisp->QueryInterface(IID_IMessengerContact, (LPVOID*)&cpExpert);
  297. if (FAILED_HR(_T("QI IMsgrUser failed: %s"), hr))
  298. goto done;
  299. hr = cpExpert->get_FriendlyName(&bstrExpertName);
  300. if (FAILED_HR(_T("get_FriendlyName failed %s"), hr))
  301. goto done;
  302. wsprintf(szHeader, _T("%d;EXP_NAME="), bstrExpertName.Length() + 9);
  303. bstrUserBlob = szHeader;
  304. bstrUserBlob.AppendBSTR(bstrExpertName);
  305. bstrUserBlob.Append("4;IM=1");
  306. disp = fact; //... it would run QI automatically.
  307. hr = disp->CreateObject_RemoteDesktopSession(
  308. (REMOTE_DESKTOP_SHARING_CLASS)VIESDESKTOP_PERMISSION_NOT_REQUIRE,
  309. SESSION_EXPIRY, // expired in 5 minutes.
  310. CComBSTR(""),
  311. bstrUserBlob,
  312. &pRCS );
  313. if (FAILED_HR(_T("CreateRemoteDesktopSession failed %s"), hr))
  314. goto done;
  315. hr = pRCS->get_ConnectParms(&bstrSalemTicket);
  316. if (FAILED_HR(_T("GetConnectParms failed: %s"), hr))
  317. goto done;
  318. // Encrypt ticket with the key and send it back.
  319. if (pPublicKeyBlob)
  320. {
  321. if (FAILED(hr = GenEncryptdNoviceBlob(pPublicKeyBlob, bstrSalemTicket, &bstrBlob)))
  322. goto done;
  323. }
  324. else
  325. {
  326. TCHAR sbuf[20];
  327. wsprintf(sbuf, _T("%d;U="), wcslen(bstrSalemTicket) + 2);
  328. bstrBlob = sbuf;
  329. bstrBlob += bstrSalemTicket;
  330. }
  331. hr = m_pSessObj->SendContextData((BSTR)bstrBlob);
  332. if (FAILED_HR(TEXT("Send Context data filed: %s"), hr))
  333. goto done;
  334. done:
  335. if (pRCS)
  336. pRCS->Release();
  337. if (pPublicKeyBlob)
  338. SysFreeString(pPublicKeyBlob);
  339. return hr;
  340. }
  341. #define IM_STATE_GET_TICKET 1
  342. #define IM_STATE_COMPLETE 2
  343. STDMETHODIMP CIMSession::ProcessContext(BSTR pContext)
  344. {
  345. TraceSpewW(L"Funct: ProcessContext %s", (pContext==NULL?L"NULL":pContext));
  346. HRESULT hr = S_OK;
  347. hr = ProcessNotify(pContext); // Is it a notification?
  348. if (SUCCEEDED(hr))
  349. {
  350. goto done;
  351. }
  352. m_iState++;
  353. m_bstrContextData = pContext;
  354. if (m_bIsInviter)
  355. {
  356. switch(m_iState)
  357. {
  358. case IM_STATE_GET_TICKET: // Received Expert ticket
  359. if (!m_bIsHSC)
  360. {
  361. hr = InviterSendSalemTicket(pContext);
  362. if (FAILED(hr))
  363. {
  364. // Need to notify expert side.
  365. Notify(RA_IM_FAILED);
  366. // Also let the local session know the status.
  367. DoSessionStatus(RA_IM_FAILED);
  368. CloseRA(); // close inviter side rcimlby.exe.
  369. }
  370. else
  371. {
  372. if (m_bExchangeUser)
  373. {
  374. // Set a timer to callback and then we call ConnectToExpert.
  375. g_pThis = this;
  376. g_timerID = SetTimer (NULL, NULL, 1000, (TIMERPROC)ConnectToExpertCallback);
  377. if (!g_timerID)
  378. {
  379. // SetTimer failed! This means that we have to bail out of the IM request
  380. // since the call to ConnectToExpert will never happen.
  381. // Need to notify expert side.
  382. Notify(RA_IM_FAILED);
  383. // Also let the local session know the status.
  384. DoSessionStatus(RA_IM_FAILED);
  385. CloseRA(); // close inviter side rcimlby.exe.
  386. }
  387. }
  388. else
  389. {
  390. CComPtr<IClassFactory> fact;
  391. CComQIPtr<IPCHUtility> disp;
  392. LONG lError;
  393. TraceSpew(_T("Connect to Expert"));
  394. hr =::CoGetClassObject(CLSID_PCHService, CLSCTX_ALL, NULL, IID_IClassFactory, (void**)&fact );
  395. if (!FAILED_HR(_T("CoGetClass CLSID_PCHService failed: %s"), hr))
  396. {
  397. disp = fact; //... it would run QI automatically.
  398. hr = disp->ConnectToExpert(m_bstrExpertTicket, 10, &lError);
  399. if (!FAILED_HR(_T("ConnectToExpert failed: %s"), hr))
  400. DoSessionStatus(RA_IM_CONNECTTOEXPERT);
  401. }
  402. CloseRA(); // close inviter side rcimlby.exe
  403. }
  404. }
  405. }
  406. else // Inviter HelpCtr status update.
  407. {
  408. DoSessionStatus(RA_IM_WAITFORCONNECT);
  409. }
  410. break;
  411. #if 0 // Connection complete: currently not used.
  412. case IM_STATE_COMPLETE:
  413. // If host is rcimlby.exe, close it.
  414. if (m_hWnd)
  415. {
  416. DestroyWindow(m_hWnd);
  417. }
  418. else
  419. {
  420. DoSessionStatus(RA_IM_COMPLETE);
  421. }
  422. break;
  423. #endif
  424. default:
  425. // Noise?
  426. break;
  427. }
  428. }
  429. else // Expert side.
  430. {
  431. switch(m_iState)
  432. {
  433. case IM_STATE_GET_TICKET: // Get Novice salem ticket
  434. // Extract this ticket to member variable and signal the call back to let host start to connect.
  435. hr = ExtractSalemTicket(pContext);
  436. if (FAILED(hr))
  437. {
  438. // need to notify Novice that connection failed.
  439. Notify(RA_IM_FAILED);
  440. DoSessionStatus(RA_IM_FAILED);
  441. }
  442. else
  443. {
  444. DoSessionStatus(RA_IM_CONNECTTOSERVER);
  445. }
  446. break;
  447. default:
  448. // Noise?
  449. break;
  450. }
  451. }
  452. done:
  453. return hr;
  454. }
  455. VOID CALLBACK ConnectToExpertCallback(
  456. HWND hwnd,
  457. UINT uMsg,
  458. UINT_PTR idEvent,
  459. DWORD dwTime
  460. )
  461. {
  462. // Kill the Timer
  463. KillTimer(NULL, g_timerID);
  464. HRESULT hr = S_OK;
  465. CComPtr<IClassFactory> fact;
  466. CComQIPtr<IPCHUtility> disp;
  467. LONG lError;
  468. TraceSpew(_T("Connect to Expert"));
  469. hr =::CoGetClassObject(CLSID_PCHService, CLSCTX_ALL, NULL, IID_IClassFactory, (void**)&fact );
  470. if (!FAILED_HR(_T("CoGetClass CLSID_PCHService failed: %s"), hr))
  471. {
  472. disp = fact; //... it would run QI automatically.
  473. hr = disp->ConnectToExpert(g_pThis->m_bstrExpertTicket, 10, &lError);
  474. if (!FAILED_HR(_T("ConnectToExpert failed: %s"), hr))
  475. g_pThis->DoSessionStatus(RA_IM_CONNECTTOEXPERT);
  476. }
  477. g_pThis->CloseRA(); // close inviter side rcimlby.exe.
  478. }
  479. ///////////////////////////////////////////////////////////////////////////////////////////
  480. // We can't notify the other party too much time. The context data can be set only 5 times.
  481. HRESULT CIMSession::ProcessNotify(BSTR pContext)
  482. {
  483. TraceSpewW(L"Funct: ProcessNotify %s", (pContext?pContext:L"NULL"));
  484. HRESULT hr = S_OK;
  485. CComPtr<IRASetting> cpSetting;
  486. CComBSTR bstrData;
  487. int lStatus;
  488. hr = cpSetting.CoCreateInstance( CLSID_RASetting, NULL, CLSCTX_INPROC_SERVER);
  489. if (FAILED_HR(_T("ISetting->CoCreateInstance failed: %s"), hr))
  490. goto done;
  491. cpSetting->get_GetPropertyInBlob(pContext, CComBSTR("NOTIFY"), &bstrData);
  492. if (bstrData.Length() == 0)
  493. {
  494. hr = E_FAIL; // Not a notification.
  495. goto done;
  496. }
  497. lStatus = _wtoi((BSTR)bstrData);
  498. switch (lStatus)
  499. {
  500. case RA_IM_COMPLETE:
  501. DoSessionStatus(RA_IM_COMPLETE);
  502. break;
  503. case RA_IM_TERMINATED:
  504. DoSessionStatus(RA_IM_TERMINATED);
  505. break;
  506. case RA_IM_FAILED:
  507. DoSessionStatus(RA_IM_FAILED);
  508. break;
  509. default: // ignore the others.
  510. break;
  511. }
  512. done:
  513. return hr;
  514. }
  515. HRESULT CIMSession::DoSessionStatus(int iState)
  516. {
  517. // Used for trace purpose.
  518. static TCHAR *szMsg[] = { _T("Unknown session status"),
  519. _T("RA_IM_COMPLETE"), // 0x1
  520. _T("RA_IM_WAITFORCONNECT"), // 0x2
  521. _T("RA_IM_CONNECTTOSERVER"), // 0x3
  522. _T("RA_IM_APPSHUTDOWN"), // 0x4
  523. _T("RA_IM_SENDINVITE"), // 0x5
  524. _T("RA_IM_ACCEPTED"), // 0x6
  525. _T("RA_IM_DECLINED"), // 0x7
  526. _T("RA_IM_NOAPP"), // 0x8
  527. _T("RA_IM_TERMINATED"), // 0x9
  528. _T("RA_IM_CANCELLED"), // 0xA
  529. _T("RA_IM_UNLOCK_WAIT"), // 0xB
  530. _T("RA_IM_UNLOCK_FAILED"), // 0xC
  531. _T("RA_IM_UNLOCK_SUCCEED"), // 0xD
  532. _T("RA_IM_UNLOCK_TIMEOUT"), // 0xE
  533. _T("RA_IM_CONNECTTOEXPERT"), // 0xF
  534. _T("RA_IM_EXPERT_TICKET_OUT")// 0x10
  535. };
  536. TCHAR *pMsg = NULL;
  537. if (iState > 0 && iState < (sizeof(szMsg) / sizeof(TCHAR*)))
  538. pMsg = szMsg[iState];
  539. else
  540. pMsg = szMsg[0];
  541. TraceSpew(_T("DoSessionStatus: %s"), pMsg);
  542. if (m_pfnSessionStatus)
  543. {
  544. DISPPARAMS disp;
  545. VARIANTARG varg[1];
  546. disp.rgvarg = varg;
  547. disp.rgdispidNamedArgs = NULL;
  548. disp.cArgs = 1;
  549. disp.cNamedArgs = 0;
  550. varg[0].vt = VT_I4;
  551. varg[0].lVal = iState;
  552. if (m_pfnSessionStatus)
  553. m_pfnSessionStatus->Invoke(0x0, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
  554. }
  555. else //Jose: If m_pfnSessionStatus is not set send message to the status dialog if it is created
  556. {
  557. if (g_StatusDlg)
  558. ::SendMessage(g_StatusDlg,MSG_STATUS,(WPARAM)iState,NULL);
  559. }
  560. if ((iState == RA_IM_TERMINATED || iState == RA_IM_FAILED) && m_bIsInviter && !m_bIsHSC)
  561. {
  562. // need to close inviter RA lobby
  563. CloseRA();
  564. }
  565. return S_OK;
  566. }
  567. HRESULT CIMSession::InitSessionEvent(IMsgrSession* pSessObj)
  568. {
  569. HRESULT hr = S_OK;
  570. if (!m_pSessionEvent)
  571. {
  572. hr = CComObject<CSessionEvent>::CreateInstance(&m_pSessionEvent);
  573. if (FAILED_HR(_T("CreateInstance SessionEvent failed: %s"), hr))
  574. goto done;
  575. m_pSessionEvent->AddRef();
  576. }
  577. m_pSessionEvent->Init(this, pSessObj);
  578. done:
  579. return hr;
  580. }
  581. HRESULT CIMSession::InitCSP(BOOL bGenPublicKey /* = TRUE */)
  582. {
  583. TraceSpew(_T("Funct: InitCSP"));
  584. HRESULT hr = S_OK;
  585. TCHAR szUser[] = _T("RemoteAssistanceIMIntegration");
  586. if (!m_hCryptProv)
  587. {
  588. // 1. If it doesn't exist then create a new one.
  589. if (!CryptAcquireContext(&m_hCryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  590. {
  591. DEBUG_MSG(_T("Create CSP failed"));
  592. hr = HRESULT_FROM_WIN32(GetLastError());
  593. goto done;
  594. }
  595. }
  596. // Get public key
  597. if(bGenPublicKey &&
  598. !m_hPublicKey &&
  599. !CryptGetUserKey(m_hCryptProv, AT_KEYEXCHANGE, &m_hPublicKey))
  600. {
  601. // Check to see if one needs to be created.
  602. if(GetLastError() == NTE_NO_KEY)
  603. {
  604. // Create an key exchange key pair.
  605. if(!CryptGenKey(m_hCryptProv,AT_KEYEXCHANGE,0,&m_hPublicKey))
  606. {
  607. DEBUG_MSG(_T("Error occurred attempting to create an exchange key."));
  608. hr = HRESULT_FROM_WIN32(GetLastError());
  609. goto done;
  610. }
  611. }
  612. else
  613. {
  614. DEBUG_MSG(_T("Error occurred when access Public key"));
  615. hr = HRESULT_FROM_WIN32(GetLastError());
  616. goto done;
  617. }
  618. }
  619. done:
  620. return hr;
  621. }
  622. HRESULT CIMSession::ExtractSalemTicket(BSTR pContext)
  623. {
  624. TraceSpewW(L"Funct: ExtraceSalemTicket %s", pContext?pContext:L"NULL");
  625. HRESULT hr = S_OK;
  626. // This ContextData could contains S (sessionkey) and U (user=ticket) name pairs.
  627. CComBSTR bstrU, bstrS;
  628. CComPtr<ISetting> cpSetting;
  629. DWORD dwLen;
  630. HCRYPTKEY hSessKey = NULL;
  631. LPBYTE pBuf = NULL;
  632. BSTR pBlob = NULL;
  633. hr = cpSetting.CoCreateInstance(CLSID_Setting, NULL, CLSCTX_INPROC_SERVER);
  634. if (FAILED_HR(_T("ISetting->CoCreateInstance failed: %s"), hr))
  635. goto done;
  636. cpSetting->get_GetPropertyInBlob(pContext, CComBSTR("U"), &bstrU);
  637. cpSetting->get_GetPropertyInBlob(pContext, CComBSTR("S"), &bstrS);
  638. dwLen = bstrS.Length();
  639. if (dwLen > 0)
  640. {
  641. // need to decrypt user ticket
  642. TraceSpewW(L"Decrypt user ticket using Expert's public key...");
  643. if (!m_hCryptProv || !m_hPublicKey)
  644. {
  645. DEBUG_MSG(_T("Can't find Cryptographic handler"));
  646. hr = FALSE;
  647. goto done;
  648. }
  649. if (FAILED(hr = StringToBinary((BSTR)bstrS, dwLen, &pBuf, &dwLen)))
  650. goto done;
  651. if (!CryptImportKey(m_hCryptProv, pBuf, dwLen, m_hPublicKey, 0, &hSessKey))
  652. {
  653. DEBUG_MSG(_T("Can't import Session Key"));
  654. hr = HRESULT_FROM_WIN32(GetLastError());
  655. goto done;
  656. }
  657. free(pBuf);
  658. pBuf=NULL;
  659. if (FAILED(hr = StringToBinary((BSTR)bstrU, bstrU.Length(), &pBuf, &dwLen)))
  660. goto done;
  661. if (!CryptDecrypt(hSessKey, 0, TRUE, 0, pBuf, &dwLen))
  662. {
  663. DEBUG_MSG(_T("Can't decrypt salem ticket"));
  664. hr = HRESULT_FROM_WIN32(GetLastError());
  665. goto done;
  666. }
  667. pBlob = SysAllocStringByteLen((char*)pBuf, dwLen);
  668. m_bstrSalemTicket.Attach(pBlob);
  669. }
  670. else
  671. {
  672. TraceSpew(_T("No expert's public key, use plain text to send salem ticket."));
  673. m_bstrSalemTicket = bstrU;
  674. }
  675. done:
  676. if (pBuf)
  677. free(pBuf);
  678. if (hSessKey)
  679. CryptDestroyKey(hSessKey);
  680. return hr;
  681. }
  682. #if 0 // No need for SP1, server or later
  683. DWORD CIMSession::GetExchangeRegValue()
  684. {
  685. CRegKey cKey;
  686. LONG lRet = 0x0;
  687. DWORD dwValue = 0x0;
  688. lRet = cKey.Open(HKEY_LOCAL_MACHINE,
  689. TEXT("SYSTEM\\CurrentControlSet\\Control\\Terminal Server"),
  690. KEY_READ );
  691. if (lRet == ERROR_SUCCESS)
  692. {
  693. lRet = cKey.QueryValue(dwValue,TEXT("UseExchangeIM"));
  694. if (lRet == ERROR_SUCCESS)
  695. {
  696. // Success
  697. }
  698. }
  699. return dwValue;
  700. }
  701. #endif
  702. ////////////////////////////////////////////////////////////////////
  703. // This is used for recipient to get his session object.
  704. STDMETHODIMP CIMSession::GetLaunchingSession(LONG lID)
  705. {
  706. HRESULT hr;
  707. IDispatch *pDisp = NULL;
  708. LONG lFlags;
  709. LONG lRet;
  710. CComPtr<IDispatch> cpDispUser;
  711. CComPtr<IMessengerContact> cpMessContact;
  712. CComBSTR bstrServiceId;
  713. CComBSTR bstrNetGUID;
  714. CRegKey cKey;
  715. if (!m_pSessMgr)
  716. {
  717. hr = CoCreateInstance (CLSID_MsgrSessionManager,
  718. NULL,
  719. CLSCTX_LOCAL_SERVER,
  720. IID_IMsgrSessionManager,
  721. (LPVOID*)&m_pSessMgr);
  722. if (FAILED_HR(_T("CoCreate IMsgrSessionManager failed: %s"), hr))
  723. goto done;
  724. }
  725. hr = UnlockSession(this);
  726. if (FAILED(hr))
  727. goto done;
  728. hr = m_pSessMgr->GetLaunchingSession(lID, (IDispatch**)&pDisp);
  729. if (FAILED_HR(TEXT("GetLaunchingSession failed: %s"), hr))
  730. goto done;
  731. hr = pDisp->QueryInterface(IID_IMsgrSession, (LPVOID*)&m_pSessObj);
  732. if (FAILED_HR(_T("QI IID_IMsgrSession failed: %s"), hr))
  733. goto done;
  734. // Grab the user
  735. hr = m_pSessObj->get_User((IDispatch**)&cpDispUser);
  736. if (FAILED_HR(_T("get_User failed: %s"), hr))
  737. goto done;
  738. // QI for the IMessengerContact
  739. hr = cpDispUser->QueryInterface(IID_IMessengerContact, (void **)&cpMessContact);
  740. if (FAILED_HR(_T("QI failed getting IID_IMessengerContact hr=%s"),hr))
  741. goto done;
  742. // Grab the Service ID from the Messenger Contact
  743. hr = cpMessContact->get_ServiceId(&bstrServiceId);
  744. if (FAILED_HR(_T("get_ServiceId failed! hr=%s"),hr))
  745. goto done;
  746. // If the service ID is {9b017612-c9f1-11d2-8d9f-0000f875c541}, then set the
  747. // flag to unlock the API.
  748. // bstrNetGUID = L"{9b017612-c9f1-11d2-8d9f-0000f875c541}"; // Messenger GUID
  749. bstrNetGUID = L"{83D4679E-B6D7-11D2-BF36-00C04FB90A03}"; // Exchange Service GUID
  750. if (bstrNetGUID == bstrServiceId)
  751. {
  752. m_bExchangeUser = TRUE;
  753. }
  754. // Else continue...
  755. // ***************************************************************************
  756. // Hook up everything
  757. if (FAILED(hr = InitSessionEvent(m_pSessObj)))
  758. goto done;
  759. hr = m_pSessObj->get_Flags(&lFlags);
  760. if (FAILED_HR(TEXT("Session Get flags failed: %s"), hr))
  761. goto done;
  762. if (lFlags & SF_INVITEE) // Inviter. Only happened when Messenger UI sends this invitation.
  763. {
  764. m_bIsInviter = FALSE;
  765. }
  766. done:
  767. if (pDisp)
  768. pDisp->Release();
  769. return hr;
  770. }
  771. HRESULT CIMSession::OnLockChallenge(BSTR pChallenge , LONG lCookie)
  772. {
  773. // Send response.
  774. //
  775. // id = [email protected]
  776. // key = L2P3B7C6V9J4T8D5
  777. //
  778. USES_CONVERSION;
  779. HRESULT hr = S_OK;
  780. CComBSTR bstrID = "[email protected]";
  781. CComBSTR bstrResponse;
  782. LPSTR pszKey = "L2P3B7C6V9J4T8D5";
  783. PSTR pszParam1 = NULL;
  784. LPSTR pszResponse = NULL;
  785. pszResponse = CAuthentication::GetAuthentication()->GetMD5Result(W2A(pChallenge), pszKey);
  786. bstrResponse = pszResponse;
  787. hr = m_pMsgrLockKey->SendResponse(bstrID, bstrResponse, lCookie);
  788. if (FAILED_HR(_T("SendResponse failed %s"), hr))
  789. goto done;
  790. done:
  791. if (pszResponse)
  792. delete pszResponse;
  793. return hr;
  794. }
  795. #define WM_APP_LOCKNOTIFY WM_APP + 0x1
  796. #define WM_APP_LOCKNOTIFY_OK WM_APP + 0x2
  797. #define WM_APP_LOCKNOTIFY_FAIL WM_APP + 0x3
  798. #define WM_APP_LOCKNOTIFY_INTHREAD WM_APP + 0x4
  799. HRESULT CIMSession::OnLockResult(BOOL fSucceed, LONG lCookie)
  800. {
  801. // Notify UnlockSession that we've get response..
  802. assert(g_hWnd);
  803. SendNotifyMessage(g_hWnd, WM_APP_LOCKNOTIFY, (WPARAM)fSucceed, NULL);
  804. DoSessionStatus(fSucceed ? RA_IM_UNLOCK_SUCCEED : RA_IM_UNLOCK_FAILED);
  805. return S_OK;
  806. }
  807. ///////////////////////////////////////////////////////////////////////
  808. // This method will be used only from inside HSC
  809. STDMETHODIMP CIMSession::HSC_Invite(IDispatch* pUser)
  810. {
  811. // Create a Invitation thread and return.
  812. // Need a lock for user to click cancel.
  813. HRESULT hr = S_OK;
  814. assert(g_hLockEvent == NULL); // If it's not NULL, there is a bug.
  815. g_hLockEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  816. if (!g_hLockEvent)
  817. {
  818. hr = HRESULT_FROM_WIN32(GetLastError());
  819. goto done;
  820. }
  821. if (pUser == NULL)
  822. {
  823. hr = E_INVALIDARG;
  824. goto done;
  825. }
  826. CoMarshalInterThreadInterfaceInStream(IID_IDispatch,pUser,&g_spInvitee);
  827. if (this->m_pfnSessionStatus)
  828. {
  829. CoMarshalInterThreadInterfaceInStream(IID_IDispatch, this->m_pfnSessionStatus, &g_spStatus);
  830. this->m_pfnSessionStatus = NULL;
  831. }
  832. if (!CreateThread(NULL, 0, HSCInviteThread, NULL, 0, NULL))
  833. {
  834. hr = HRESULT_FROM_WIN32(GetLastError());
  835. goto done;
  836. }
  837. //Jose: If m_pfnSessionStatus is not set the component displays its own status dialog.
  838. if (!this->m_pfnSessionStatus)
  839. {
  840. if (IDCANCEL == m_StatusDlg.DoModal())
  841. {
  842. Notify(RA_IM_CANCELLED);
  843. }
  844. }
  845. done:
  846. if (FAILED(hr) && g_hLockEvent != NULL)
  847. {
  848. CloseHandle(g_hLockEvent);
  849. g_hLockEvent = NULL;
  850. }
  851. return hr;
  852. }
  853. DWORD WINAPI HSCInviteThread(LPVOID lpParam)
  854. {
  855. CComObject<CIMSession> *pThis = NULL;
  856. HRESULT hr;
  857. CComBSTR bstrAPPID(C_RA_APPID);
  858. CComPtr<IDispatch> cpDisp;
  859. LockStatus ls=LOCK_NOTINITIALIZED;
  860. hr = CComObject<CIMSession>::CreateInstance(&pThis);
  861. if (FAILED(hr))
  862. {
  863. goto done;
  864. }
  865. if (g_spStatus) // Rebuild StatusCallback
  866. {
  867. CoGetInterfaceAndReleaseStream(g_spStatus,IID_IDispatch,(void**)&pThis->m_pfnSessionStatus);
  868. g_spStatus = NULL;
  869. }
  870. // 1. Create SessionManager
  871. if (!pThis->m_pSessMgr)
  872. {
  873. hr = UnlockSession(pThis);
  874. if (FAILED(hr))
  875. goto done;
  876. }
  877. // Check Lock status
  878. hr = pThis->m_pMsgrLockKey->get_Status(&ls);
  879. if (ls != LOCK_UNLOCKED)
  880. pThis->DoSessionStatus(RA_IM_UNLOCK_SUCCEED);
  881. else
  882. pThis->DoSessionStatus(RA_IM_UNLOCK_FAILED);
  883. if (ls != LOCK_UNLOCKED)
  884. {
  885. pThis->DoSessionStatus(RA_IM_UNLOCK_FAILED);
  886. goto done;
  887. }
  888. // 3. create session object
  889. hr = pThis->m_pSessMgr->CreateSession((IDispatch**)&cpDisp);
  890. if (FAILED(hr))
  891. goto done;
  892. hr = cpDisp->QueryInterface(IID_IMsgrSession, (void **)&pThis->m_pSessObj);
  893. if (FAILED(hr))
  894. goto done;
  895. // Hook up enent sink
  896. if (FAILED(hr = pThis->InitSessionEvent(pThis->m_pSessObj)))
  897. goto done;
  898. // 4. Set session option
  899. hr = pThis->m_pSessObj->put_Application((BSTR)bstrAPPID);
  900. if (FAILED_HR(_T("put_Application failed: %s"), hr))
  901. goto done;
  902. // OK. I'm from HelpCtr.
  903. pThis->m_bIsHSC = TRUE;
  904. // Invite
  905. if (!cpDisp)
  906. cpDisp.Release();
  907. CoGetInterfaceAndReleaseStream(g_spInvitee,IID_IDispatch,(void**)&cpDisp);
  908. g_spInvitee = NULL;
  909. if (g_bActionCancel) // It's cancelled already.
  910. goto done;
  911. if(FAILED(hr = pThis->Invite(cpDisp)))
  912. goto done;
  913. // This loop is only used if user wants to cancel this invitation.
  914. while (1)
  915. {
  916. // User has 10 minutes to click cancel.
  917. // If regular connection doesn't happen in 10 minutes, it timeout too.
  918. DWORD dwWaitState = WaitForSingleObject(g_hLockEvent, RA_TIMEOUT_USER);
  919. if (dwWaitState == WAIT_OBJECT_0 && g_bActionCancel == TRUE) // at this moment, we don't have anyother action.
  920. {
  921. hr = pThis->m_pSessObj->Cancel(MSGR_E_CANCEL, NULL);
  922. }
  923. break; // For now, we always get out of the loop.
  924. }
  925. done:
  926. if (g_hLockEvent)
  927. {
  928. CloseHandle(g_hLockEvent);
  929. g_hLockEvent = NULL;
  930. }
  931. if (pThis)
  932. pThis->Release();
  933. g_bActionCancel = FALSE; //reset this global variable.
  934. return hr;
  935. }
  936. ////////////////////////////////////////////////////////////////
  937. // This function only used from inside HSC
  938. HRESULT CIMSession::Invite(IDispatch* pUser)
  939. {
  940. HRESULT hr = S_OK;
  941. if (m_pSessObj == NULL)
  942. {
  943. hr = E_FAIL;
  944. goto done;
  945. }
  946. // Send invitation without ticket. Ticket will be sent from ContextData.
  947. hr = m_pSessObj->Invite(pUser, NULL);
  948. if (FAILED_HR(TEXT("Invite failed %s"), hr))
  949. goto done;
  950. DoSessionStatus(RA_IM_SENDINVITE);
  951. done:
  952. return hr;
  953. }
  954. STDMETHODIMP CIMSession::Notify(int iIMStatus)
  955. {
  956. HRESULT hr = S_OK;
  957. TCHAR szHeader[1024];
  958. CComBSTR bstrData;
  959. if (iIMStatus == RA_IM_CANCELLED || iIMStatus == RA_IM_CLOSE_INVITE_UI) // Doesn't need to use ContextData to notify this msg
  960. {
  961. assert(m_bIsHSC == TRUE); // Only helpctr scenario would do this.
  962. if (g_hLockEvent) // if it's NULL, that means this thread has already terminated itself.
  963. {
  964. g_bActionCancel = (iIMStatus == RA_IM_CANCELLED); // It's possible that user just want to close the UI.
  965. SetEvent(g_hLockEvent);
  966. }
  967. goto done;
  968. }
  969. if (m_pSessObj)
  970. {
  971. wsprintf(szHeader, _T("%d;NOTIFY=%d"), GetDigit(iIMStatus) + 7, iIMStatus);
  972. bstrData = szHeader;
  973. if (bstrData.Length() > 0)
  974. {
  975. hr = m_pSessObj->SendContextData((BSTR)bstrData);
  976. if (FAILED_HR(_T("Notify: SendContextData failed %s"), hr))
  977. goto done;
  978. }
  979. }
  980. done:
  981. return S_OK;
  982. }
  983. ////////////////////////////////////////////////////////////////
  984. // This function sends expert ticket to user through ContextData
  985. STDMETHODIMP CIMSession::SendOutExpertTicket(BSTR bstrTicket)
  986. {
  987. TraceSpewW(L"Funct: SendOutExpertTicket %s", bstrTicket?bstrTicket:L"NULL");
  988. HRESULT hr = S_OK;
  989. CComBSTR bstrPublicKeyBlob;
  990. CComBSTR bstrBlob;
  991. DWORD dwCount=0, dwLen;
  992. TCHAR szHeader[100];
  993. if (!m_pSessObj)
  994. return FALSE;
  995. // 1. Get public blob.
  996. if (FAILED(hr = InitCSP()))
  997. goto done;
  998. // 2. Create Blob with predefined format.
  999. if(FAILED(hr = GetKeyExportString(m_hPublicKey, 0, PUBLICKEYBLOB, &bstrPublicKeyBlob, &dwCount)))
  1000. goto done;
  1001. dwLen = wcslen(bstrTicket);
  1002. wsprintf(szHeader, _T("%d;ET="), dwLen+3);
  1003. bstrBlob = szHeader;
  1004. bstrBlob.AppendBSTR(bstrTicket);
  1005. if (dwCount)
  1006. {
  1007. wsprintf(szHeader, _T("%d;PK="), dwCount+3);
  1008. bstrBlob.Append(szHeader);
  1009. bstrBlob += bstrPublicKeyBlob;
  1010. }
  1011. // 3. Send it out.
  1012. hr = m_pSessObj->SendContextData((BSTR)bstrBlob);
  1013. if (FAILED(hr))
  1014. goto done;
  1015. DoSessionStatus(RA_IM_EXPERT_TICKET_OUT);
  1016. done:
  1017. return hr;
  1018. }
  1019. HRESULT CIMSession::GetKeyExportString(HCRYPTKEY hKey, HCRYPTKEY hExKey, DWORD dwBlobType, BSTR* pBlob, DWORD *pdwCount)
  1020. {
  1021. HRESULT hr = S_OK;
  1022. DWORD dwKeyLen;
  1023. LPBYTE pBinBuf = NULL;
  1024. if (!pBlob)
  1025. return FALSE;
  1026. // Calculate how big the destination buffer size we need.
  1027. if (!CryptExportKey(hKey, hExKey, dwBlobType, 0, NULL, &dwKeyLen))
  1028. {
  1029. DEBUG_MSG(_T("Can't calculate public key length"));
  1030. hr = HRESULT_FROM_WIN32(GetLastError());
  1031. goto done;
  1032. }
  1033. pBinBuf = (LPBYTE)malloc(dwKeyLen);
  1034. if (!pBinBuf)
  1035. {
  1036. hr = E_OUTOFMEMORY;
  1037. goto done;
  1038. }
  1039. if (!CryptExportKey(hKey, hExKey, dwBlobType, 0, pBinBuf, &dwKeyLen))
  1040. {
  1041. DEBUG_MSG(_T("Can't write public key to blob"));
  1042. hr = HRESULT_FROM_WIN32(GetLastError());
  1043. goto done;
  1044. }
  1045. if (FAILED(hr=BinaryToString(pBinBuf, dwKeyLen, pBlob, pdwCount)))
  1046. goto done;
  1047. done:
  1048. if (pBinBuf)
  1049. free(pBinBuf);
  1050. return hr;
  1051. }
  1052. HRESULT CIMSession::BinaryToString(LPBYTE pBinBuf, DWORD dwLen, BSTR* pBlob, DWORD *pdwCount)
  1053. {
  1054. HRESULT hr = S_OK;
  1055. TCHAR *pBuf = NULL;
  1056. CComBSTR bstrBlob;
  1057. if (!pBlob)
  1058. return FALSE;
  1059. if (!CryptBinaryToString(pBinBuf, dwLen, CRYPT_STRING_BASE64, NULL, pdwCount))
  1060. {
  1061. DEBUG_MSG(_T("Can't calculate string len for blob converstion"));
  1062. hr = HRESULT_FROM_WIN32(GetLastError());
  1063. goto done;
  1064. }
  1065. if (NULL == (pBuf = (TCHAR*)malloc(*pdwCount * sizeof(TCHAR))))
  1066. {
  1067. hr = E_OUTOFMEMORY;
  1068. goto done;
  1069. }
  1070. if (!CryptBinaryToString(pBinBuf, dwLen, CRYPT_STRING_BASE64, pBuf, pdwCount))
  1071. {
  1072. DEBUG_MSG(_T("Can't convert key blob to string"));
  1073. hr = HRESULT_FROM_WIN32(GetLastError());
  1074. goto done;
  1075. }
  1076. bstrBlob.Append(pBuf);
  1077. *pBlob = bstrBlob.Detach();
  1078. done:
  1079. if (pBuf)
  1080. free(pBuf);
  1081. return hr;
  1082. }
  1083. HRESULT CIMSession::StringToBinary(BSTR pBlob, DWORD dwCount, LPBYTE *ppBuf, DWORD* pdwLen)
  1084. {
  1085. HRESULT hr=S_OK;
  1086. DWORD dwSkip, dwFlag;
  1087. if (!CryptStringToBinary(pBlob, dwCount, CRYPT_STRING_BASE64, NULL, pdwLen, &dwSkip, &dwFlag))
  1088. {
  1089. DEBUG_MSG(_T("Can't calculate needed binary buffer length"));
  1090. hr = HRESULT_FROM_WIN32(GetLastError());
  1091. goto done;
  1092. }
  1093. *ppBuf = (LPBYTE)malloc(*pdwLen);
  1094. if (!CryptStringToBinary(pBlob, dwCount, CRYPT_STRING_BASE64,
  1095. *ppBuf, pdwLen, &dwSkip, &dwFlag))
  1096. {
  1097. DEBUG_MSG(_T("Can't convert to binary blob"));
  1098. hr = HRESULT_FROM_WIN32(GetLastError());
  1099. goto done;
  1100. }
  1101. done:
  1102. return hr;
  1103. }
  1104. HRESULT CIMSession::UninitObjects()
  1105. {
  1106. HRESULT hr = S_OK;
  1107. // Make sure we don't follow the null pointer
  1108. if (m_pSessMgr && m_pSessionMgrEvent)
  1109. {
  1110. m_pSessionMgrEvent->Unadvise();
  1111. }
  1112. return hr;
  1113. }
  1114. HRESULT UnlockSession(CIMSession* pThis)
  1115. {
  1116. TraceSpew(_T("Funct: UnlockSession"));
  1117. HRESULT hr = S_OK;
  1118. MSG msg;
  1119. CComPtr<IConnectionPointContainer> cpCPC;
  1120. CComPtr<IConnectionPoint> cpCP;
  1121. LockStatus ls=LOCK_NOTINITIALIZED;
  1122. BOOL bRet;
  1123. assert(pThis->m_pSessMgr == NULL);
  1124. hr = CoCreateInstance( CLSID_MsgrSessionManager,
  1125. NULL,
  1126. CLSCTX_LOCAL_SERVER,
  1127. IID_IMsgrSessionManager,
  1128. (LPVOID*)&pThis->m_pSessMgr);
  1129. if (FAILED_HR(_T("CoCreate CLSID_MsgrSessionManager failed: %s"), hr))
  1130. goto done;
  1131. // 2. Create Lock object
  1132. hr = pThis->m_pSessMgr->QueryInterface(IID_IMsgrLock, (LPVOID*)&pThis->m_pMsgrLockKey);
  1133. if (FAILED_HR(_T("Can't create MsgrLock object: %s"), hr))
  1134. goto done;
  1135. // 2. Hook SessionManager events
  1136. pThis->m_pSessionMgrEvent = new CSessionMgrEvent(pThis);
  1137. if (!pThis->m_pSessionMgrEvent)
  1138. {
  1139. hr = E_OUTOFMEMORY;
  1140. goto done;
  1141. }
  1142. pThis->m_pSessionMgrEvent->AddRef();
  1143. hr = pThis->m_pSessMgr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpCPC);
  1144. if (FAILED_HR(_T("QI: IConnectionPointContainer of SessionMgr failed %s"), hr))
  1145. goto done;
  1146. hr = cpCPC->FindConnectionPoint(DIID_DMsgrSessionManagerEvents, &cpCP);
  1147. if (FAILED_HR(_T("FindConnectionPoint DMessengerEvents failed %s"), hr))
  1148. goto done;
  1149. hr = pThis->m_pSessionMgrEvent->Advise(cpCP);
  1150. if (FAILED(hr))
  1151. goto done;
  1152. g_hWnd = InitInstance(g_hInstance, 0);
  1153. // Set up credential with server.
  1154. hr = pThis->m_pMsgrLockKey->get_Status(&ls);
  1155. if (ls == LOCK_UNLOCKED)
  1156. {
  1157. hr = S_OK;
  1158. goto done;
  1159. }
  1160. SetTimer(g_hWnd, RA_TIMER_UNLOCK_ID, RA_TIMEOUT_UNLOCK, NULL); // 3 minutes.
  1161. // Send challenge
  1162. pThis->DoSessionStatus(RA_IM_UNLOCK_WAIT);
  1163. hr = pThis->m_pMsgrLockKey->RequestChallenge(70); // Random number: 70
  1164. if (FAILED_HR(_T("RequestChallenge failed: %s"), hr))
  1165. goto done;
  1166. // Wait until permission get granted or timeout.
  1167. while (bRet = GetMessage(&msg, NULL, 0, 0))
  1168. {
  1169. if (msg.message == WM_APP_LOCKNOTIFY_INTHREAD)
  1170. {
  1171. hr = ((BOOL)msg.wParam)?S_OK:E_FAIL;
  1172. break;
  1173. }
  1174. TranslateMessage(&msg);
  1175. DispatchMessage(&msg);
  1176. }
  1177. done:
  1178. if (g_hWnd)
  1179. {
  1180. // kill control window.
  1181. DestroyWindow(g_hWnd);
  1182. g_hWnd = NULL;
  1183. }
  1184. TraceSpew(_T("Leave UnlockSession hr=%s"),GetStringFromError(hr));
  1185. return hr;
  1186. }
  1187. HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
  1188. {
  1189. HWND hWnd;
  1190. WNDCLASSEX wcex;
  1191. wcex.cbSize = sizeof(WNDCLASSEX);
  1192. wcex.style = CS_HREDRAW | CS_VREDRAW;
  1193. wcex.lpfnWndProc = WndProc;
  1194. wcex.cbClsExtra = 0;
  1195. wcex.cbWndExtra = 0;
  1196. wcex.hInstance = hInstance;
  1197. wcex.hIcon = NULL;
  1198. wcex.hCursor = NULL;
  1199. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  1200. wcex.lpszMenuName = NULL;
  1201. wcex.lpszClassName = szWindowClass;
  1202. wcex.hIconSm = NULL;
  1203. RegisterClassEx(&wcex);
  1204. hWnd = CreateWindow(szWindowClass, TEXT("Remote Assistance"), WS_OVERLAPPEDWINDOW,
  1205. CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL);
  1206. return hWnd;
  1207. }
  1208. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  1209. {
  1210. switch (message)
  1211. {
  1212. case WM_CREATE:
  1213. TraceSpew(_T("WndProc: WM_CREATE called"));
  1214. g_hWnd = hWnd;
  1215. break;
  1216. case WM_TIMER:
  1217. {
  1218. if (wParam == RA_TIMER_UNLOCK_ID)
  1219. {
  1220. TraceSpew(_T("WndProc: WM_TIMER RA_TIMER_UNLOCK_ID fired"));
  1221. PostMessage(NULL, WM_APP_LOCKNOTIFY_INTHREAD, (WPARAM)FALSE, NULL);
  1222. }
  1223. }
  1224. break;
  1225. case WM_APP_LOCKNOTIFY:
  1226. {
  1227. //PostQuitMessage(0); // Used for single thread
  1228. TraceSpew(_T("WndProc: WM_APP_LOCKNOTIFY fired"));
  1229. KillTimer(g_hWnd, RA_TIMER_UNLOCK_ID);
  1230. PostMessage(NULL, WM_APP_LOCKNOTIFY_INTHREAD, wParam, lParam);
  1231. }
  1232. break;
  1233. default:
  1234. return DefWindowProc(hWnd, message, wParam, lParam);
  1235. }
  1236. return 0;
  1237. }