Source code of Windows XP (NT5)
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.

2335 lines
62 KiB

  1. #include "precomp.h"
  2. #include "resource.h"
  3. #include "pfnwldap.h"
  4. #include "conf.h"
  5. #include "cr.h"
  6. #include <cstring.hpp>
  7. #include <ulsreg.h>
  8. #include "NmLdap.h"
  9. #include "version.h"
  10. #include "call.h"
  11. #include "confapi.h"
  12. #include "confutil.h"
  13. #include "dirutil.h"
  14. // One global instance
  15. CNmLDAP* g_pLDAP = NULL;
  16. CPing* g_pPing = NULL;
  17. // This flag indicates weather or not we have loaded the LDAP dll ( WLDAP::Init() )
  18. /*static*/ bool CNmLDAP::ms_bLdapDLLLoaded = false;
  19. ////////////////////////////////////////////////////////////////////////////////////////
  20. // Helper Macros
  21. // the ldap_modify function takes an LDAPMod** type
  22. // If it took an array of LDAPMod ( an LDAPMod* type )
  23. // Then life would be easier for us to make static lists
  24. // Unfortunately, this is not how it works, so we have macros
  25. // to pretty things up ( and hopefully not to confuse anyone )
  26. // This is to declare an LDAPMod with one val
  27. #define DECLARE_LDAP_MOD( t, x, y )\
  28. LPTSTR aVals_##x[] = { y, NULL };\
  29. LDAPMod LDAPMod_##x = { t, _T(#x), aVals_##x }
  30. // This is to declare an LDAPMod with 2 vals
  31. #define DECLARE_LDAP_MOD2( t, x, y1, y2 )\
  32. LPTSTR aVals_##x[] = { y1, y2, NULL };\
  33. LDAPMod LDAPMod_##x = { t, _T(#x), aVals_##x }
  34. #define LDAP_MOD_ENTRY( x ) &LDAPMod_##x
  35. #define LDAP_MOD_ADD_ENTRY( x ) &LDAPMod_add_##x
  36. ////////////////////////////////////////////////////////////////////////////////////////
  37. // Some helpful deffinitions
  38. #define LDAP_REFRESH_BASE_DN _T("objectClass=RTPerson")
  39. #define RESOLVE_USER_SEARCH_FILTER _T("(&(objectClass=RTPerson)(cn=%s))")
  40. //NOTE: The LDAP_REFRESH_FILTER... notice the sttl=10... aparently, this is how you request the
  41. // server to restart the TTL countdown... the sttl= value can be anything BUT '*' ( the value you would
  42. // expecte it to be... ) This is a link to the "Dynamir Ldap Extension RFC" if you want more info
  43. // http://www.critical-angle.com/ldapworld/draft-ietf-asid-ldapv3ext-04.txt
  44. #define LDAP_REFRESH_FILTER _T("(&(objectClass=RTPerson)(cn=%s)(sttl=10))")
  45. #define LOGIN_USER_FILTER _T("c=-,o=Microsoft,cn=%s,objectClass=RTPerson")
  46. #define IP_ADDRESS_ATTR_NAME _T("sipaddress")
  47. #define STTL_ATTR_NAME _T("sttl")
  48. #define CNmLDAP_WCNAME _T("CNmLDAP_WCNAME")
  49. #define LDAP_MODOP_ADDAPP _T("0")
  50. #define LDAP_MODOP_DELETEAPP _T("1")
  51. #define LDAP_MODOP_MODIFYUSER _T("2")
  52. #define LDAP_MODOP_MODIFYAPP _T("3")
  53. #define LDAP_ATTR_FALSE _T("0")
  54. #define LDAP_ATTR_TRUE _T("1")
  55. #define LDAP_ATTR_BUSINESS _T("2")
  56. // We are not using the country name anymore, but we can't leave the country
  57. // field blank ( empty string ), it is just the way that SiteServer is written...
  58. #define LDAP_ATTR_DUMMY_COUNTRYNAME _T("-")
  59. #define INVALID_MSG_ID ((ULONG) -1) // same as ldap_****()
  60. #define LDAP_RESULT_ERROR ((ULONG) -1)
  61. #define LDAP_RESULT_TIMEOUT 0
  62. // When the bind helper thread function gets the result to bind_s function
  63. // it passes it to this thread via PostMessage( m_hWndHidder, WM_USER_BIND_COMPLETE, ret, err )
  64. #define WM_USER_BIND_COMPLETE (WM_APP + 1) // wParam = Return code from bind_s, lParam = GetLastError()
  65. #define WM_NEED_RELOGON (WM_APP + 2)
  66. CNmLDAP::CNmLDAP()
  67. : m_State(Uninitialized),
  68. m_pKeepAlive(NULL),
  69. m_hWndHidden(NULL),
  70. m_pLdap(NULL),
  71. m_ResultPollTimer(0),
  72. m_LogoffTimer(0),
  73. m_uMsgID(INVALID_MSG_ID),
  74. m_CurrentOp(Op_NoOp),
  75. m_bVisible(true),
  76. m_bDirty(false),
  77. m_bRefreshAfterBindCompletes(false),
  78. m_bLogoffAfterBindCompletes(false),
  79. m_bSendInCallAttrWhenDone(false),
  80. m_bInCall(false),
  81. m_hEventWaitForLogoffDone(NULL),
  82. m_hBindThread(NULL),
  83. m_iPort(DEFAULT_LDAP_PORT),
  84. m_bAudioHardware(false),
  85. m_bVideoHardware(false)
  86. {
  87. DBGENTRY(CNmLDAP::CNmLDAP);
  88. SetLoggedOn( false );
  89. DBGEXIT(CNmLDAP::CNmLDAP);
  90. }
  91. CNmLDAP::~CNmLDAP()
  92. {
  93. DBGENTRY(CNmLDAP::~CNmLDAP);
  94. if (NULL != m_pKeepAlive)
  95. {
  96. m_pKeepAlive->End(TRUE); // synchronous end
  97. m_pKeepAlive = NULL;
  98. }
  99. if((m_State != Idle) && (m_State != Uninitialized))
  100. {
  101. // Make sure that someone at least has already called Logoff()
  102. ASSERT((LoggingOff == m_State) || (Op_Logoff == m_CurrentOp));
  103. // We are logging off, but we would like to wait a while to make sure that
  104. // all of our async operations are completed... We don't want to wait too long,
  105. // Though... Basically we set a timer to pass a message to us... if we get that
  106. // message, we signal m_hEventWaitForLogoffDone.... if any of the async operations
  107. // complete during this time, they will also signal this event....We make sure to
  108. // hawe a message loop ( AtlWaitWithWessageLoop ) so that our wndproc will be called
  109. m_hEventWaitForLogoffDone = CreateEvent(NULL,TRUE,FALSE,NULL);
  110. if(m_hEventWaitForLogoffDone)
  111. {
  112. m_LogoffTimer = ::SetTimer(m_hWndHidden, WaitForLogoffTimer, LOGOFF_WAIT_INTERVAL, NULL);
  113. if(m_LogoffTimer)
  114. {
  115. AtlWaitWithMessageLoop(m_hEventWaitForLogoffDone);
  116. }
  117. CloseHandle(m_hEventWaitForLogoffDone);
  118. m_hEventWaitForLogoffDone = NULL;
  119. }
  120. else
  121. {
  122. ERROR_OUT(("Create Event failed"));
  123. }
  124. if( Binding == m_State )
  125. {
  126. WARNING_OUT(("Aborting an ldap_bind because we are closing down in ~CNmLDAP"));
  127. TerminateThread(m_hBindThread, 0);
  128. CloseHandle(m_hBindThread);
  129. }
  130. else if(Idle != m_State)
  131. {
  132. WARNING_OUT(("Aborting pending LDAP operation in ~CNmLDAP"));
  133. _AbandonAllAndSetToIdle();
  134. }
  135. }
  136. if( NULL != m_hWndHidden )
  137. {
  138. DestroyWindow( m_hWndHidden );
  139. m_hWndHidden = NULL;
  140. }
  141. m_State = Uninitialized;
  142. SetLoggedOn( false );
  143. DBGEXIT(CNmLDAP::~CNmLDAP);
  144. }
  145. HRESULT CNmLDAP::_bCallChangedHelper()
  146. {
  147. TRACE_OUT(("CNmLDAP::_bCallChangedHelper:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  148. HRESULT hr = S_OK;
  149. if( IsLoggedOn() || IsBusy() )
  150. {
  151. if(LoggedIn == m_State)
  152. {
  153. // We simply have to bind and call ldap_modify
  154. m_CurrentOp = Op_Modifying_InCallAttr;
  155. hr = _BindAsync();
  156. }
  157. else if((SettingAppInfo == m_State) ||
  158. (ModifyingAttrs == m_State) ||
  159. (AddingUser == m_State)
  160. )
  161. {
  162. // the other states will be calling ldap_mod( user Attributes ) which will pick up
  163. // the change to m_bInCall. The states listed above are the ones that occur after
  164. // the user attributes have been sent to the server... There are also other states
  165. // that logoff, so they don't care about sending the update to the user attribute to the server
  166. m_bSendInCallAttrWhenDone = true;
  167. }
  168. }
  169. TRACE_OUT(("CNmLDAP::_bCallChangedHelper:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  170. return hr;
  171. }
  172. HRESULT CNmLDAP::OnCallStarted()
  173. {
  174. DBGENTRY(CNmLDAP::OnCallStarted);
  175. TRACE_OUT(("CNmLDAP::OnCallStarted:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  176. HRESULT hr = S_OK;
  177. ASSERT(ms_bLdapDLLLoaded);
  178. if( !m_bInCall )
  179. {
  180. m_bInCall = true;
  181. hr = _bCallChangedHelper();
  182. }
  183. TRACE_OUT(("CNmLDAP::OnCallStarted:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  184. DBGEXIT_HR(CNmLDAP::OnCallStarted,hr);
  185. return hr;
  186. }
  187. HRESULT CNmLDAP::OnCallEnded()
  188. {
  189. DBGENTRY(CNmLDAP::OnCallEnded);
  190. TRACE_OUT(("CNmLDAP::OnCallEnded:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  191. HRESULT hr = S_OK;
  192. ASSERT(ms_bLdapDLLLoaded);
  193. if( m_bInCall )
  194. {
  195. m_bInCall = false;
  196. hr = _bCallChangedHelper();
  197. }
  198. TRACE_OUT(("CNmLDAP::OnCallEnded:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  199. DBGEXIT_HR(CNmLDAP::OnCallEnded,hr);
  200. return hr;
  201. }
  202. bool CNmLDAP::IsLoggedOn() const
  203. {
  204. DBGENTRY(CNmLDAP::IsLoggedOn);
  205. TRACE_OUT(("CNmLDAP::IsLoggedOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  206. bool bRet = ( ( LoggedIn == m_State ) ||
  207. ( ModifyingAttrs == m_State ) ||
  208. ( Op_Refresh_Logoff == m_CurrentOp ) ||
  209. ( Op_Modifying_InCallAttr == m_CurrentOp )
  210. );
  211. TRACE_OUT(("CNmLDAP::IsLoggedOn:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
  212. DBGEXIT(CNmLDAP::IsLoggedOn);
  213. return bRet;
  214. }
  215. bool CNmLDAP::IsLoggingOn() const
  216. {
  217. DBGENTRY(CNmLDAP::IsLoggingOn);
  218. TRACE_OUT(("CNmLDAP::IsLoggingOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  219. bool bRet = ( ( AddingUser == m_State ) ||
  220. ( UserAdded == m_State ) ||
  221. ( SettingAppInfo == m_State ) ||
  222. ( Op_Logon == m_CurrentOp )
  223. );
  224. TRACE_OUT(("CNmLDAP::IsLoggingOn:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
  225. DBGEXIT(CNmLDAP::IsLoggingOn);
  226. return bRet;
  227. }
  228. bool CNmLDAP::IsBusy() const
  229. {
  230. DBGENTRY(CNmLDAP::IsBusy);
  231. TRACE_OUT(("CNmLDAP::IsBusy:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  232. bool bRet = !((LoggedIn == m_State) || ( Idle == m_State ) || (Uninitialized == m_State));
  233. TRACE_OUT(("CNmLDAP::IsBusy:exit(%d): m_State:%d: m_currentOp:%d", bRet, m_State, m_CurrentOp));
  234. DBGEXIT(CNmLDAP::IsBusy);
  235. return bRet;
  236. }
  237. void CNmLDAP::_MakeStatusText(UINT uResID, LPTSTR psz, UINT cch) const
  238. {
  239. const TCHAR * const server = CDirectoryManager::get_displayName( m_strCurrentServer );
  240. LPCTSTR pszFmt = RES2T(uResID);
  241. LPTSTR pszStr = reinterpret_cast<LPTSTR>(_alloca(lstrlen(pszFmt) + lstrlen(server) - 1));
  242. if(pszStr)
  243. {
  244. wsprintf(pszStr, pszFmt, server);
  245. lstrcpyn(psz, pszStr, cch);
  246. }
  247. }
  248. HRESULT CNmLDAP::GetStatusText(LPTSTR psz, int cch, UINT *idIcon ) const
  249. {
  250. DBGENTRY(CNmLDAP::GetStatusText);
  251. UINT idDummy;
  252. if (NULL == idIcon)
  253. {
  254. // Just so we don't need to do switches all over the place
  255. idIcon = &idDummy;
  256. }
  257. HRESULT hr = S_OK;
  258. TRACE_OUT(("m_State = %d", m_State));
  259. TRACE_OUT(("CNmLDAP::GetStatusText:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  260. if(psz)
  261. {
  262. if( cch > 1 )
  263. {
  264. switch(m_State)
  265. {
  266. case LoggedIn:
  267. case ModifyingAttrs:
  268. *idIcon = IDI_NET;
  269. _MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
  270. break;
  271. case Binding:
  272. {
  273. switch(m_CurrentOp)
  274. {
  275. case Op_Logon:
  276. *idIcon = IDS_STATUS_WAITING;
  277. _MakeStatusText(ID_STATUS_LOGON_FORMAT, psz, cch);
  278. break;
  279. case Op_Modifying_InCallAttr:
  280. *idIcon = IDI_NET;
  281. _MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
  282. break;
  283. case Op_Refresh_Logoff:
  284. if( lstrcmpi(m_strServer,m_strCurrentServer))
  285. {
  286. *idIcon = IDS_STATUS_WAITING;
  287. _MakeStatusText(ID_STATUS_LOGOFF_FORMAT, psz, cch);
  288. }
  289. else
  290. {
  291. *idIcon = IDI_NET;
  292. _MakeStatusText(ID_STATUS_LOGGEDON_FORMAT, psz, cch);
  293. }
  294. break;
  295. case Op_Logoff:
  296. *idIcon = IDI_NETGRAY;
  297. lstrcpyn(psz, RES2T(ID_STATUS_LOGGEDOFF), cch);
  298. break;
  299. }
  300. break;
  301. }
  302. case AddingUser:
  303. case UserAdded:
  304. case SettingAppInfo:
  305. *idIcon = IDS_STATUS_WAITING;
  306. _MakeStatusText(ID_STATUS_LOGON_FORMAT, psz, cch);
  307. break;
  308. case LoggingOff:
  309. *idIcon = IDS_STATUS_WAITING;
  310. _MakeStatusText(ID_STATUS_LOGOFF_FORMAT, psz, cch);
  311. break;
  312. case Bound:
  313. case Idle:
  314. case Uninitialized:
  315. *idIcon = IDI_NETGRAY;
  316. lstrcpyn(psz, RES2T(ID_STATUS_LOGGEDOFF), cch);
  317. break;
  318. default:
  319. ERROR_OUT(("Not a regognized state: %d", m_State));
  320. break;
  321. }
  322. }
  323. else
  324. {
  325. hr = E_INVALIDARG;
  326. }
  327. }
  328. else
  329. {
  330. hr = E_POINTER;
  331. }
  332. TRACE_OUT(("CNmLDAP::GetStatusText:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  333. DBGEXIT_HR(CNmLDAP::GetStatusText,hr);
  334. return hr;
  335. }
  336. HRESULT CNmLDAP::OnSettingsChanged()
  337. {
  338. DBGENTRY(CNmLDAP::OnSettingsChanged);
  339. TRACE_OUT(("CNmLDAP::OnSettingsChanged:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  340. HRESULT hr = S_OK;
  341. ASSERT(ms_bLdapDLLLoaded);
  342. if(S_OK == _GetUserSettingsFromRegistryAndGlobals())
  343. {
  344. hr = OnReLogon();
  345. }
  346. TRACE_OUT(("CNmLDAP::OnSettingsChanged:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  347. DBGEXIT_HR(CNmLDAP::OnSettingsChanged,hr);
  348. return hr;
  349. }
  350. HRESULT CNmLDAP::OnReLogon(void)
  351. {
  352. HRESULT hr = S_OK;
  353. ASSERT(ms_bLdapDLLLoaded);
  354. m_bDirty = true;
  355. if(IsLoggedOn() || IsBusy())
  356. {
  357. hr = _RefreshServer();
  358. }
  359. return hr;
  360. }
  361. HRESULT CNmLDAP::_RefreshServer()
  362. {
  363. DBGENTRY(CNmLDAP::_RefreshServer);
  364. TRACE_OUT(("CNmLDAP::_RefreshServer:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  365. HRESULT hr = S_OK;
  366. ASSERT(ms_bLdapDLLLoaded);
  367. if( m_bDirty )
  368. {
  369. if(Binding == m_State)
  370. {
  371. if(Op_Logon == m_CurrentOp) // we are logging on and haven't sent any user information yet
  372. {
  373. // Check to see if we have not changed the server name
  374. if( !lstrcmpi(m_strServer, CDirectoryManager::get_defaultServer() ) )
  375. {
  376. // Simply update the user settings
  377. _GetUserSettingsFromRegistryAndGlobals();
  378. }
  379. else
  380. {
  381. // Since the server has changed, we have to do a logoff(from old)/logon(to new)
  382. _InternalLogoff(true);
  383. }
  384. }
  385. else if(m_CurrentOp != Op_Logoff)
  386. {
  387. // If we are in the middle of a bind operation, which happens
  388. // in another thread, we just have to wait for it to complete
  389. // before we go any further
  390. m_bRefreshAfterBindCompletes = true;
  391. }
  392. }
  393. else if(Idle == m_State)
  394. {
  395. _GetUserSettingsFromRegistryAndGlobals();
  396. LogonAsync();
  397. }
  398. else
  399. {
  400. _InternalLogoff(true);
  401. }
  402. }
  403. TRACE_OUT(("CNmLDAP::_RefreshServer:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  404. DBGEXIT_HR(CNmLDAP::_RefreshServer,hr);
  405. return hr;
  406. }
  407. void CNmLDAP::_AbandonAllAndSetState(eState new_state)
  408. {
  409. TRACE_OUT(("CNmLDAP::_AbandonAllAndSetState:enter: new_state=%d, m_State:%d: m_currentOp:%d", new_state, m_State, m_CurrentOp));
  410. if(m_ResultPollTimer)
  411. {
  412. ::KillTimer(m_hWndHidden,m_ResultPollTimer);
  413. m_ResultPollTimer = 0;
  414. }
  415. if(m_pLdap)
  416. {
  417. if( INVALID_MSG_ID != m_uMsgID )
  418. {
  419. WLDAP::ldap_abandon(m_pLdap, m_uMsgID);
  420. }
  421. WLDAP::ldap_unbind(m_pLdap);
  422. }
  423. m_pLdap = NULL;
  424. m_uMsgID = INVALID_MSG_ID;
  425. m_State = new_state;
  426. m_CurrentOp = Op_NoOp;
  427. SetLoggedOn( IsLoggedOn() );
  428. TRACE_OUT(("CNmLDAP::_AbandonAllAndSetState:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  429. }
  430. HRESULT CNmLDAP::_InternalLogoff(bool bRefreshLogoff)
  431. {
  432. DBGENTRY(CNmLDAP::_InternalLogoff);
  433. TRACE_OUT(("CNmLDAP::_InternalLogoff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  434. HRESULT hr = S_OK;
  435. ASSERT(ms_bLdapDLLLoaded);
  436. if( ( LoggingOff != m_State ) && ( Idle != m_State ) )
  437. {
  438. if(bRefreshLogoff)
  439. {
  440. m_CurrentOp = Op_Refresh_Logoff;
  441. // If the server names are different, this means
  442. // that we should display "logging off" XXX
  443. if( lstrcmpi(m_strServer, m_strCurrentServer) )
  444. {
  445. _OnLoggingOff();
  446. }
  447. }
  448. else
  449. {
  450. _OnLoggingOff();
  451. m_CurrentOp = Op_Logoff;
  452. }
  453. if( LoggedIn == m_State )
  454. {
  455. hr = _BindAsync();
  456. }
  457. else if( Binding == m_State )
  458. {
  459. m_bLogoffAfterBindCompletes = true;
  460. }
  461. else if( (INVALID_MSG_ID != m_uMsgID ) && (NULL != m_pLdap ))
  462. {
  463. // Kill the timer
  464. ASSERT(m_ResultPollTimer);
  465. ::KillTimer(m_hWndHidden,m_ResultPollTimer);
  466. m_ResultPollTimer = 0;
  467. // Abandon the current op
  468. WLDAP::ldap_abandon(m_pLdap, m_uMsgID);
  469. m_uMsgID = INVALID_MSG_ID;
  470. m_State = Bound;
  471. SetLoggedOn( IsLoggedOn() );
  472. }
  473. if(Bound == m_State)
  474. {
  475. ASSERT(m_pLdap);
  476. _DeleteUser();
  477. }
  478. }
  479. TRACE_OUT(("CNmLDAP::_InternalLogoff:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  480. DBGEXIT_HR(CNmLDAP::_InternalLogoff,hr);
  481. return hr;
  482. }
  483. HRESULT CNmLDAP::Logoff()
  484. {
  485. DBGENTRY(CNmLDAP::Logoff);
  486. TRACE_OUT(("CNmLDAP::Logoff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  487. HRESULT hr = _InternalLogoff(false);
  488. TRACE_OUT(("CNmLDAP::Logoff:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  489. DBGEXIT_HR(CNmLDAP::Logoff,hr);
  490. return hr;
  491. }
  492. HRESULT CNmLDAP::Initialize( HINSTANCE hInst )
  493. {
  494. HRESULT hr = S_OK;
  495. DBGENTRY(CNmLDAP::Initialize);
  496. TRACE_OUT(("CNmLDAP::Initialize:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  497. ASSERT( Uninitialized == m_State );
  498. if( ms_bLdapDLLLoaded || SUCCEEDED( hr = WLDAP::Init()))
  499. {
  500. ms_bLdapDLLLoaded = true;
  501. ////////////////////////////////////////
  502. // Initialize user data
  503. _GetUserSettingsFromRegistryAndGlobals();
  504. ////////////////////////////////////////
  505. // Initialize hidden Window
  506. WNDCLASS wcHidden =
  507. {
  508. 0L,
  509. _sWndProc,
  510. 0,
  511. 0,
  512. hInst,
  513. NULL,
  514. NULL,
  515. NULL,
  516. NULL,
  517. CNmLDAP_WCNAME
  518. };
  519. if(RegisterClass(&wcHidden))
  520. {
  521. m_hWndHidden = ::CreateWindow( CNmLDAP_WCNAME, g_szEmpty, 0, 0, 0, 0, 0, NULL, NULL, hInst, this);
  522. if( m_hWndHidden )
  523. {
  524. m_State = Idle;
  525. SetLoggedOn( IsLoggedOn() );
  526. }
  527. else
  528. {
  529. hr = HRESULT_FROM_WIN32(GetLastError());
  530. }
  531. }
  532. else
  533. {
  534. hr = HRESULT_FROM_WIN32(GetLastError());
  535. }
  536. }
  537. else
  538. {
  539. ERROR_OUT(("WLDAP::Init failed ( could not load wldap32.dll? )"));
  540. }
  541. TRACE_OUT(("CNmLDAP::Initialize:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  542. DBGEXIT_HR(CNmLDAP::Initialize,hr);
  543. return hr;
  544. }
  545. HRESULT CNmLDAP::_GetUserSettingsFromRegistryAndGlobals()
  546. {
  547. DBGENTRY(CNmLDAP::_GetUserSettingsFromRegistryAndGlobals);
  548. TRACE_OUT(("CNmLDAP::_GetUserSettingsFromRegistryAndGlobals:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  549. HRESULT hr = S_FALSE; // this would indicate that nothing changed
  550. RegEntry reULS(ISAPI_CLIENT_KEY, HKEY_CURRENT_USER);
  551. if(lstrcmpi(m_strSurName, reULS.GetString(ULS_REGKEY_LAST_NAME)))
  552. {
  553. hr = S_OK;
  554. m_strSurName = reULS.GetString(ULS_REGKEY_LAST_NAME);
  555. }
  556. if(lstrcmpi(m_strGivenName, reULS.GetString(ULS_REGKEY_FIRST_NAME)))
  557. {
  558. hr = S_OK;
  559. m_strGivenName = reULS.GetString(ULS_REGKEY_FIRST_NAME);
  560. }
  561. if(lstrcmpi(m_strEmailName, reULS.GetString(REGVAL_ULS_EMAIL_NAME)))
  562. {
  563. hr = S_OK;
  564. m_strEmailName = reULS.GetString(REGVAL_ULS_EMAIL_NAME);
  565. }
  566. if(lstrcmpi(m_strComment, reULS.GetString(ULS_REGKEY_COMMENTS)))
  567. {
  568. hr = S_OK;
  569. m_strComment = reULS.GetString(ULS_REGKEY_COMMENTS);
  570. }
  571. if(lstrcmpi(m_strLocation, reULS.GetString(ULS_REGKEY_LOCATION)))
  572. {
  573. hr = S_OK;
  574. m_strLocation = reULS.GetString(ULS_REGKEY_LOCATION);
  575. }
  576. if(lstrcmpi(m_strSecurityToken, reULS.GetString(ULS_REGKEY_CLIENT_ID)))
  577. {
  578. hr = S_OK;
  579. m_strSecurityToken = reULS.GetString(ULS_REGKEY_CLIENT_ID);
  580. }
  581. if(*m_strSecurityToken == '\0')
  582. { // The string was not found...
  583. // When we log onto the LDAP server, we pass a fairly unique ID
  584. // This is passed as the value to the ssecurity attribute
  585. // In the case that NetMeeting goes away without actually logging
  586. // off of the ILS server, when NetMeeting tries to log back on,
  587. // it will pass this unique ID... if the server has not closed the
  588. // session account for the user, the server uses this ID to "authenticate"
  589. // that we are the same user as the last session...
  590. TCHAR szNewClientID[MAX_PATH];
  591. wsprintf(szNewClientID,"%lu", ::GetTickCount());
  592. m_strSecurityToken = szNewClientID;
  593. reULS.SetValue(ULS_REGKEY_CLIENT_ID,szNewClientID);
  594. hr = S_OK;
  595. }
  596. if( lstrcmpi(m_strServer, CDirectoryManager::get_defaultServer()))
  597. {
  598. hr = S_OK;
  599. m_strServer = CDirectoryManager::get_defaultServer();
  600. m_iPort = DEFAULT_LDAP_PORT;
  601. }
  602. if(m_bVisible != (!reULS.GetNumber(ULS_REGKEY_DONT_PUBLISH, REGVAL_ULS_DONT_PUBLISH_DEFAULT)))
  603. {
  604. m_bVisible = !reULS.GetNumber(ULS_REGKEY_DONT_PUBLISH, REGVAL_ULS_DONT_PUBLISH_DEFAULT);
  605. hr = S_OK;
  606. }
  607. if(m_bAudioHardware != (0 != (g_uMediaCaps & CAPFLAG_SEND_AUDIO)))
  608. {
  609. m_bAudioHardware = (0 != (g_uMediaCaps & CAPFLAG_SEND_AUDIO));
  610. hr = S_OK;
  611. }
  612. if(m_bVideoHardware != (0 != (g_uMediaCaps & CAPFLAG_SEND_VIDEO)))
  613. {
  614. m_bVideoHardware = (0 != (g_uMediaCaps & CAPFLAG_SEND_VIDEO));
  615. hr = S_OK;
  616. }
  617. TRACE_OUT(("CNmLDAP::_GetUserSettingsFromRegistryAndGlobals:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  618. DBGEXIT_HR(CNmLDAP::_GetUserSettingsFromRegistryAndGlobals,hr);
  619. return hr;
  620. }
  621. HRESULT CNmLDAP::LogonAsync( LPCTSTR pcszServer /*=NULL*/)
  622. {
  623. HRESULT hr = S_OK;
  624. DBGENTRY(CNmLDAP::LogonAsync);
  625. TRACE_OUT(("CNmLDAP::LogonAsync:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  626. // Idle // Normal logon
  627. //Binding
  628. // Op_Logoff // Change it to logon refresh
  629. // Bound // ldap_umbind-> Logon normal
  630. // LoggingOff // Change to Op_Refresh_Logoff
  631. // Uninitialized // return error
  632. // AddingUser // do nothing
  633. // UserAdded // do nothing
  634. // SettingAppInfo // do nothing
  635. // ModifyingAttrs // do nothing
  636. // LoggedIn // do nothing
  637. // Op_Refresh_Logoff // Do nothing
  638. // Op_Modifying_InCallAttr // Do Nothing
  639. // Op_Logon // Do Nothing
  640. if( Uninitialized != m_State)
  641. {
  642. if(Bound == m_State)
  643. {
  644. _AbandonAllAndSetToIdle();
  645. }
  646. if(Idle == m_State)
  647. {
  648. if(pcszServer)
  649. {
  650. m_strServer = pcszServer;
  651. m_iPort = DEFAULT_LDAP_PORT;
  652. }
  653. else
  654. {
  655. if(!IsLoggedOn())
  656. {
  657. _GetUserSettingsFromRegistryAndGlobals();
  658. }
  659. }
  660. m_strCurrentServer = m_strServer;
  661. g_pCCallto->SetIlsServerName( m_strCurrentServer );
  662. TCHAR* szDN = new TCHAR[ lstrlen( LOGIN_USER_FILTER ) + lstrlen(m_strEmailName) + 1 ];
  663. if( szDN )
  664. {
  665. wsprintf(szDN, LOGIN_USER_FILTER, m_strEmailName);
  666. m_strCurrentDN = szDN;
  667. delete [] szDN;
  668. m_CurrentOp = Op_Logon;
  669. hr = _BindAsync();
  670. if( SUCCEEDED(hr) )
  671. {
  672. _OnLoggingOn();
  673. }
  674. }
  675. else
  676. {
  677. hr = E_OUTOFMEMORY;
  678. }
  679. }
  680. else if((Op_Logoff == m_CurrentOp) || (LoggingOff == m_State))
  681. {
  682. m_CurrentOp = Op_Refresh_Logoff;
  683. }
  684. }
  685. else
  686. {
  687. hr = E_FAIL;
  688. }
  689. TRACE_OUT(("CNmLDAP::LogonAsync:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  690. DBGEXIT_HR(CNmLDAP::LogonAsync,hr);
  691. return hr;
  692. }
  693. HRESULT CNmLDAP::_BindAsync()
  694. {
  695. DBGENTRY(CNmLDAP::_BindAsync);
  696. TRACE_OUT(("CNmLDAP::_BindAsync:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  697. ASSERT(( LoggedIn == m_State ) || ( Idle == m_State ));
  698. ASSERT( m_CurrentOp != Op_NoOp );
  699. ASSERT(m_hBindThread == NULL);
  700. HRESULT hr = S_OK;
  701. // Set our state to Binding
  702. m_State = Binding;
  703. SetLoggedOn( IsLoggedOn() );
  704. // Start the bind in another thread
  705. DWORD dwBindThreadID = 0;
  706. m_hBindThread = CreateThread(NULL, 0, _sAsyncBindThreadFn, this, 0, &dwBindThreadID);
  707. if(NULL == m_hBindThread)
  708. {
  709. ERROR_OUT(("CreateThread failed"));
  710. hr = HRESULT_FROM_WIN32(GetLastError());
  711. WLDAP::ldap_unbind(m_pLdap);
  712. m_pLdap = NULL;
  713. m_CurrentOp = Op_NoOp;
  714. m_State = Idle;
  715. }
  716. SetLoggedOn( IsLoggedOn() );
  717. TRACE_OUT(("CNmLDAP::_BindAsync:exit(0x%08X): m_State:%d: m_currentOp:%d", hr, m_State, m_CurrentOp));
  718. DBGEXIT_HR(CNmLDAP::_BindAsync,hr);
  719. return hr;
  720. }
  721. /*static*/
  722. DWORD CNmLDAP::_sAsyncBindThreadFn(LPVOID lpParameter)
  723. {
  724. DBGENTRY(CNmLDAP::_sAsyncBindThreadFn);
  725. ASSERT(lpParameter);
  726. CNmLDAP* pThis = reinterpret_cast<CNmLDAP*>(lpParameter);
  727. ASSERT(pThis);
  728. ULONG ulRet = LDAP_OPERATIONS_ERROR;
  729. ULONG ulErr = ERROR_INVALID_HANDLE;
  730. if( pThis )
  731. {
  732. WSADATA wsaData;
  733. if( WSAStartup( 0x0101, &wsaData ) == 0 )
  734. {
  735. if( wsaData.wVersion > 1 )
  736. {
  737. pThis->m_pLdap = WLDAP::ldap_init( const_cast<LPTSTR>((LPCTSTR)pThis->m_strCurrentServer), pThis->m_iPort );
  738. if( pThis->m_pLdap )
  739. {
  740. ::SetLastError(NO_ERROR);
  741. ulRet = WLDAP::ldap_bind_s(pThis->m_pLdap, const_cast<LPTSTR>(g_szEmpty), const_cast<LPTSTR>(g_szEmpty), LDAP_AUTH_SIMPLE );
  742. if( ulRet == LDAP_SUCCESS )
  743. {
  744. ulErr = ::GetLastError();
  745. ::SendMessage(pThis->m_hWndHidden, WM_USER_BIND_COMPLETE, ulRet, ulErr);
  746. }
  747. else if( pThis->m_iPort == DEFAULT_LDAP_PORT )
  748. {
  749. WLDAP::ldap_unbind( pThis->m_pLdap );
  750. pThis->m_pLdap = WLDAP::ldap_init( const_cast<LPTSTR>((LPCTSTR)pThis->m_strCurrentServer), ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
  751. if( pThis->m_pLdap != NULL )
  752. {
  753. ::SetLastError(NO_ERROR);
  754. ulRet = WLDAP::ldap_bind_s(pThis->m_pLdap, const_cast<LPTSTR>(g_szEmpty), const_cast<LPTSTR>(g_szEmpty), LDAP_AUTH_SIMPLE );
  755. if( ulRet == LDAP_SUCCESS )
  756. {
  757. pThis->m_iPort = ALTERNATE_LDAP_PORT;
  758. }
  759. ulErr = ::GetLastError();
  760. ::SendMessage(pThis->m_hWndHidden, WM_USER_BIND_COMPLETE, ulRet, ulErr);
  761. }
  762. else
  763. {
  764. TRACE_OUT(("ldap_init failed"));
  765. pThis->m_State = Idle;
  766. pThis->m_CurrentOp = Op_NoOp;
  767. }
  768. }
  769. }
  770. else
  771. {
  772. TRACE_OUT(("ldap_init failed"));
  773. pThis->m_State = Idle;
  774. pThis->m_CurrentOp = Op_NoOp;
  775. }
  776. }
  777. WSACleanup();
  778. }
  779. }
  780. DBGEXIT(CNmLDAP::_sAsyncBindThreadFn);
  781. return ulRet;
  782. }
  783. LRESULT CNmLDAP::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  784. {
  785. LRESULT lr = TRUE;
  786. DBGENTRY(CNmLDAP::WndProc);
  787. switch( uMsg )
  788. {
  789. case WM_USER_BIND_COMPLETE:
  790. _OnUserBindComplete((INT)wParam, (DWORD)lParam);
  791. break;
  792. case WM_TIMER:
  793. lr = FALSE; // This means that we handle the message
  794. _OnTimer(wParam);
  795. break;
  796. case WM_NEED_RELOGON:
  797. OnReLogon();
  798. break;
  799. default:
  800. lr = DefWindowProc(hwnd, uMsg, wParam, lParam);
  801. break;
  802. }
  803. DBGEXIT_ULONG(CNmLDAP::WndProc,lr);
  804. return lr;
  805. }
  806. void CNmLDAP::_OnTimer(UINT_PTR TimerID)
  807. {
  808. DBGENTRY(CNmLDAP::_OnTimer);
  809. TRACE_OUT(("CNmLDAP::_OnTimer:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  810. // We check the timer ID values first because we may have killed the timer,
  811. // and the message couldv be simply vestigal ( that means left over from an earlier time)...
  812. if(m_LogoffTimer && (WaitForLogoffTimer == TimerID))
  813. {
  814. // We are waiting in the distructor for an async operation to complete
  815. // and we have waited too long... kill the timer and set the m_hEventWaitForLogoffDone event
  816. ::KillTimer(m_hWndHidden, m_LogoffTimer);
  817. m_LogoffTimer = 0;
  818. if(m_hEventWaitForLogoffDone)
  819. {
  820. SetEvent(m_hEventWaitForLogoffDone);
  821. }
  822. }
  823. else if( (INVALID_MSG_ID != m_uMsgID) && m_ResultPollTimer && (PollForResultTimer == TimerID ))
  824. {
  825. ASSERT(m_pLdap);
  826. ::KillTimer( m_hWndHidden, m_ResultPollTimer );
  827. m_ResultPollTimer = 0;
  828. LDAPMessage *pMsg = NULL;
  829. LDAP_TIMEVAL TimeoutVal = { 0, 0 };
  830. INT res = WLDAP::ldap_result( m_pLdap, m_uMsgID, LDAP_MSG_ALL, &TimeoutVal, &pMsg );
  831. if( 0 == res )
  832. {
  833. // ldap_result timedout
  834. m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
  835. if( !m_ResultPollTimer )
  836. {
  837. ERROR_OUT(("SetTimer failed!"));
  838. _AbandonAllAndRecoverState();
  839. }
  840. }
  841. else if( LDAP_RESULT_ERROR == res )
  842. {
  843. ERROR_OUT(("ldap_result failed"));
  844. _AbandonAllAndRecoverState();
  845. }
  846. else
  847. {
  848. // We got the result, so reset this
  849. m_uMsgID = INVALID_MSG_ID;
  850. if( AddingUser == m_State )
  851. {
  852. _OnAddingUserResult(pMsg->lm_returncode);
  853. WLDAP::ldap_msgfree(pMsg);
  854. }
  855. else if( ( SettingAppInfo == m_State ) || ( ModifyingAttrs == m_State ) )
  856. {
  857. _OnSettingAppInfoOrModifyingAttrsResult(pMsg->lm_returncode);
  858. WLDAP::ldap_msgfree(pMsg);
  859. }
  860. else if( LoggingOff == m_State )
  861. {
  862. _OnLoggingOffResult(pMsg->lm_returncode);
  863. WLDAP::ldap_msgfree(pMsg);
  864. }
  865. }
  866. }
  867. TRACE_OUT(("CNmLDAP::_OnTimer:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  868. DBGEXIT(CNmLDAP::_OnTimer);
  869. }
  870. void CNmLDAP::_OnUserBindComplete(INT LdapResult, DWORD LastError )
  871. {
  872. DBGENTRY(CNmLDAP::_OnUserBindComplete);
  873. TRACE_OUT(("CNmLDAP::_OnUserBindComplete:enter(%d): m_State:%d: m_currentOp:%d", LdapResult, m_State, m_CurrentOp));
  874. ASSERT(m_hBindThread);
  875. ASSERT(Binding == m_State);
  876. CloseHandle(m_hBindThread);
  877. m_hBindThread = NULL;
  878. if(LDAP_SUCCESS == LdapResult)
  879. {
  880. m_State = Bound;
  881. SetLoggedOn( IsLoggedOn() );
  882. if( m_bRefreshAfterBindCompletes )
  883. {
  884. // If a refresh is attempted while
  885. // the bind operation is in progress
  886. // we just wait for the bind to complete
  887. // then we well do the refresh
  888. m_bRefreshAfterBindCompletes = false;
  889. _RefreshServer();
  890. }
  891. else if( m_bLogoffAfterBindCompletes )
  892. {
  893. m_bLogoffAfterBindCompletes = false;
  894. _DeleteUser();
  895. }
  896. else
  897. {
  898. if( Op_Logon == m_CurrentOp )
  899. {
  900. m_CurrentOp = Op_NoOp;
  901. _AddUser();
  902. }
  903. else if( Op_Logoff == m_CurrentOp )
  904. {
  905. m_CurrentOp = Op_NoOp;
  906. _DeleteUser();
  907. }
  908. else if( Op_Refresh_Logoff == m_CurrentOp )
  909. {
  910. _DeleteUser();
  911. }
  912. else if( Op_Modifying_InCallAttr == m_CurrentOp )
  913. {
  914. m_CurrentOp = Op_NoOp;
  915. _ModifyInCallAttr();
  916. }
  917. }
  918. }
  919. else
  920. {
  921. eCurrentOp OldOp = m_CurrentOp;
  922. _AbandonAllAndRecoverState(OldOp);
  923. if( ( Op_Refresh_Logoff == OldOp ) && ( lstrcmpi( m_strCurrentServer, m_strServer ) ) )
  924. {
  925. // If the server names have changed...
  926. // Suppose that the server you are logged on to
  927. // goes down and then you change the server that you want
  928. // to be logged on to ( before you have any indication that
  929. // the server has gone down... You want to log off the old server
  930. // But the server is not available... We are basically going to
  931. // ignore the fact that there was a problem logging off
  932. // from the server, and we are going to simply log on to the new server
  933. _OnLoggedOff();
  934. LogonAsync();
  935. }
  936. else if( Op_Logoff == OldOp )
  937. {
  938. // We don't have to put up a message box...
  939. _OnLoggedOff();
  940. }
  941. else
  942. {
  943. if( (LDAP_SERVER_DOWN == LdapResult) || (LDAP_TIMEOUT == LdapResult) )
  944. {
  945. if (Op_Modifying_InCallAttr == OldOp)
  946. {
  947. ERROR_OUT(("ldap_bind for InCallAttr returns server-down or timeout"));
  948. }
  949. else
  950. {
  951. ::PostConfMsgBox(IDS_ULSLOGON_BADSERVER);
  952. _OnLoggedOff();
  953. }
  954. }
  955. else
  956. {
  957. ERROR_OUT(("ldap_bind returned error 0x%08x LdapResult, GetLastError == 0x%08x", LdapResult, LastError));
  958. }
  959. }
  960. }
  961. TRACE_OUT(("CNmLDAP::_OnUserBindComplete:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  962. DBGEXIT(CNmLDAP::_OnUserBindComplete);
  963. }
  964. void CNmLDAP::_OnLoggingOffResult(int Result)
  965. {
  966. DBGENTRY(CNmLDAP::_OnLoggingOffResult);
  967. TRACE_OUT(("CNmLDAP::_OnLoggingOffResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
  968. if( (LDAP_SUCCESS == Result) || (LDAP_NO_SUCH_OBJECT == Result) || (LDAP_SERVER_DOWN == Result))
  969. {
  970. // We are waiting in the destructor for the ldap logof operations to complete
  971. // Now that it has, we hawe to signal the destructor unblocks
  972. if(m_hEventWaitForLogoffDone)
  973. {
  974. SetEvent(m_hEventWaitForLogoffDone);
  975. }
  976. _OnLoggedOff();
  977. }
  978. else
  979. {
  980. ERROR_OUT(("Ldap Error 0x%08x", Result));
  981. }
  982. WLDAP::ldap_unbind(m_pLdap);
  983. m_State = Idle;
  984. m_pLdap = NULL;
  985. SetLoggedOn( IsLoggedOn() );
  986. if( Op_Refresh_Logoff == m_CurrentOp )
  987. {
  988. m_CurrentOp = Op_NoOp;
  989. LogonAsync();
  990. }
  991. TRACE_OUT(("CNmLDAP::_OnLoggingOffResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  992. DBGEXIT(CNmLDAP::_OnLoggingOffResult);
  993. }
  994. void CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult(int Result)
  995. {
  996. DBGENTRY(CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult);
  997. TRACE_OUT(("CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
  998. if( LDAP_SUCCESS == Result)
  999. {
  1000. // start the keep alive thread
  1001. if (NULL != m_pKeepAlive)
  1002. {
  1003. m_pKeepAlive->Start();
  1004. }
  1005. if(SettingAppInfo == m_State)
  1006. {
  1007. m_State = LoggedIn;
  1008. SetLoggedOn( IsLoggedOn() );
  1009. _OnLoggedOn();
  1010. }
  1011. else
  1012. {
  1013. m_State = LoggedIn;
  1014. SetLoggedOn( IsLoggedOn() );
  1015. }
  1016. if( m_bSendInCallAttrWhenDone )
  1017. {
  1018. m_bSendInCallAttrWhenDone = false;
  1019. _ModifyInCallAttr();
  1020. }
  1021. else
  1022. {
  1023. WLDAP::ldap_unbind(m_pLdap);
  1024. if(m_ResultPollTimer)
  1025. {
  1026. ::KillTimer(m_hWndHidden,m_ResultPollTimer);
  1027. m_ResultPollTimer = 0;
  1028. }
  1029. m_uMsgID = INVALID_MSG_ID;
  1030. m_pLdap = NULL;
  1031. m_State = LoggedIn;
  1032. SetLoggedOn( IsLoggedOn() );
  1033. }
  1034. }
  1035. else
  1036. {
  1037. ERROR_OUT( ("Ldap Error 0x%08x, DN=%s", Result, m_strCurrentDN) );
  1038. if (ModifyingAttrs == m_State && NULL != m_pKeepAlive)
  1039. {
  1040. _AbandonAllAndRecoverState();
  1041. if(LDAP_NO_SUCH_OBJECT == Result)
  1042. {
  1043. _OnLoggedOff();
  1044. LogonAsync();
  1045. }
  1046. }
  1047. else
  1048. {
  1049. _AbandonAllAndSetToIdle();
  1050. _OnLoggedOff();
  1051. if(LDAP_NO_SUCH_OBJECT == Result)
  1052. {
  1053. LogonAsync();
  1054. }
  1055. }
  1056. }
  1057. TRACE_OUT(("CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1058. DBGEXIT(CNmLDAP::_OnSettingAppInfoOrModifyingAttrsResult);
  1059. }
  1060. void CNmLDAP::_OnAddingUserResult( int Result)
  1061. {
  1062. DBGENTRY(CNmLDAP::_OnAddingUserResult);
  1063. TRACE_OUT(("CNmLDAP::_OnAddingUserResult:enter(%d): m_State:%d: m_currentOp:%d", Result, m_State, m_CurrentOp));
  1064. if( LDAP_SUCCESS == Result )
  1065. {
  1066. m_State = UserAdded;
  1067. SetLoggedOn( IsLoggedOn() );
  1068. _SetAppInfo();
  1069. }
  1070. else
  1071. {
  1072. UINT uStringID;
  1073. switch( Result )
  1074. {
  1075. case LDAP_ALREADY_EXISTS:
  1076. uStringID = IDS_ULSLOGON_DUPLICATE;
  1077. break;
  1078. case LDAP_NAMING_VIOLATION:
  1079. uStringID = IDS_ULSLOGON_WORD_FILTER;
  1080. break;
  1081. case LDAP_UNWILLING_TO_PERFORM:
  1082. uStringID = IDS_ILLEGALEMAILNAME;
  1083. break;
  1084. case LDAP_UNDEFINED_TYPE:
  1085. case LDAP_SERVER_DOWN:
  1086. // W2K server returns this under heavy load situations...
  1087. uStringID = IDS_ULSLOGON_ERROR;
  1088. break;
  1089. default:
  1090. uStringID = IDS_ULSLOGON_ERROR;
  1091. ERROR_OUT( ("Ldap Error 0x%08x, DN=%s", Result, m_strCurrentDN) );
  1092. break;
  1093. }
  1094. ::PostConfMsgBox( uStringID );
  1095. _OnLoggedOff();
  1096. WLDAP::ldap_unbind(m_pLdap);
  1097. m_pLdap = NULL;
  1098. m_State = Idle;
  1099. SetLoggedOn( IsLoggedOn() );
  1100. }
  1101. TRACE_OUT(("CNmLDAP::_OnAddingUserResult:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1102. DBGEXIT(CNmLDAP::_OnAddingUserResult);
  1103. }
  1104. /*static*/
  1105. LRESULT CNmLDAP::_sWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1106. {
  1107. LRESULT lr = 0;
  1108. if( WM_NCCREATE != uMsg )
  1109. {
  1110. CNmLDAP* pNmLdap = reinterpret_cast<CNmLDAP*>( ::GetWindowLongPtr( hwnd, GWLP_USERDATA ) );
  1111. if( pNmLdap )
  1112. {
  1113. lr = pNmLdap->WndProc( hwnd, uMsg, wParam, lParam );
  1114. }
  1115. }
  1116. else
  1117. {
  1118. lr = TRUE; // This means to continue creating the window
  1119. CREATESTRUCT* pCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
  1120. if( pCreateStruct )
  1121. {
  1122. ::SetWindowLongPtr( hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));
  1123. }
  1124. }
  1125. return lr;
  1126. }
  1127. void CNmLDAP::_SetAppInfo()
  1128. {
  1129. DBGENTRY(CNmLDAP::_SetInfo);
  1130. TRACE_OUT(("CNmLDAP::_SetInfo:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1131. ASSERT(NULL != m_pLdap);
  1132. ASSERT(UserAdded == m_State);
  1133. ASSERT(INVALID_MSG_ID == m_uMsgID);
  1134. // These are the app attribute vals
  1135. DECLARE_LDAP_MOD(LDAP_MOD_ADD, smodop, LDAP_MODOP_ADDAPP);
  1136. DECLARE_LDAP_MOD(LDAP_MOD_ADD, sappid, _T("ms-netmeeting"));
  1137. DECLARE_LDAP_MOD(LDAP_MOD_ADD, smimetype, _T("text/iuls"));
  1138. DECLARE_LDAP_MOD(LDAP_MOD_ADD, sappguid, _T("008aff194794cf118796444553540000"));
  1139. DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sprotid, _T("t120"), _T("h323"));
  1140. DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sprotmimetype, _T("text/t120"), _T("text/h323"));
  1141. DECLARE_LDAP_MOD2(LDAP_MOD_ADD, sport, _T("1503"), _T("1720"));
  1142. // This is the app mod array
  1143. LDAPMod *apModApp[] =
  1144. {
  1145. LDAP_MOD_ENTRY(smodop),
  1146. LDAP_MOD_ENTRY(sappid),
  1147. LDAP_MOD_ENTRY(smimetype),
  1148. LDAP_MOD_ENTRY(sappguid),
  1149. LDAP_MOD_ENTRY(sprotid),
  1150. LDAP_MOD_ENTRY(sprotmimetype),
  1151. LDAP_MOD_ENTRY(sport),
  1152. NULL
  1153. };
  1154. m_uMsgID = WLDAP::ldap_modify( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apModApp );
  1155. if( INVALID_MSG_ID != m_uMsgID )
  1156. {
  1157. m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
  1158. ASSERT(m_ResultPollTimer);
  1159. m_State = SettingAppInfo;
  1160. }
  1161. else
  1162. {
  1163. DWORD dwErr;
  1164. ERROR_OUT(("ldap_modify returned error 0x%08x", (WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_ERROR_NUMBER, &dwErr), dwErr)));
  1165. WLDAP::ldap_unbind(m_pLdap);
  1166. m_pLdap = NULL;
  1167. m_State = Idle;
  1168. }
  1169. SetLoggedOn( IsLoggedOn() );
  1170. TRACE_OUT(("CNmLDAP::_SetInfo:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1171. DBGEXIT(CNmLDAP::_SetInfo);
  1172. }
  1173. void CNmLDAP::_ModifyInCallAttr()
  1174. {
  1175. TRACE_OUT(("CNmLDAP::_ModifyInCallAttr:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1176. DECLARE_LDAP_MOD(LDAP_MOD_REPLACE, smodop, LDAP_MODOP_MODIFYUSER);
  1177. DECLARE_LDAP_MOD(LDAP_MOD_REPLACE, ilsA26214430, m_bInCall ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE);
  1178. LDAPMod *apMod[] =
  1179. {
  1180. LDAP_MOD_ENTRY(smodop),
  1181. LDAP_MOD_ENTRY(ilsA26214430),
  1182. NULL
  1183. };
  1184. TRACE_OUT(("About to modify InCallAttrs for this person: %s", m_strCurrentDN));
  1185. m_uMsgID = WLDAP::ldap_modify( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apMod );
  1186. if( INVALID_MSG_ID != m_uMsgID )
  1187. {
  1188. m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
  1189. ASSERT(m_ResultPollTimer);
  1190. m_State = ModifyingAttrs;
  1191. }
  1192. else
  1193. {
  1194. DWORD dwErr;
  1195. ERROR_OUT(("ldap_modify returned error 0x%08x", (WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_ERROR_NUMBER, &dwErr), dwErr)));
  1196. WLDAP::ldap_unbind(m_pLdap);
  1197. m_pLdap = NULL;
  1198. m_State = (NULL != m_pKeepAlive) ? LoggedIn : Idle; // restore the state
  1199. }
  1200. SetLoggedOn( IsLoggedOn() );
  1201. TRACE_OUT(("CNmLDAP::_ModifyInCallAttr:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1202. }
  1203. void CNmLDAP::_DeleteUser()
  1204. {
  1205. DBGENTRY(CNmLDAP::_DeleteUser);
  1206. TRACE_OUT(("CNmLDAP::_DeleteUser:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1207. // end the keep alive thread
  1208. if (NULL != m_pKeepAlive)
  1209. {
  1210. m_pKeepAlive->End();
  1211. m_pKeepAlive = NULL;
  1212. }
  1213. ASSERT(NULL != m_pLdap);
  1214. ASSERT(Bound == m_State);
  1215. ASSERT(INVALID_MSG_ID == m_uMsgID);
  1216. m_uMsgID = WLDAP::ldap_delete(m_pLdap, const_cast<LPTSTR>((LPCTSTR)(m_strCurrentDN)));
  1217. if( INVALID_MSG_ID != m_uMsgID )
  1218. {
  1219. m_State = LoggingOff;
  1220. m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
  1221. ASSERT(m_ResultPollTimer);
  1222. }
  1223. else
  1224. {
  1225. WLDAP::ldap_unbind(m_pLdap);
  1226. m_pLdap = NULL;
  1227. m_State = Idle;
  1228. }
  1229. SetLoggedOn( IsLoggedOn() );
  1230. TRACE_OUT(("CNmLDAP::_DeleteUser:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1231. DBGEXIT(CNmLDAP::_DeleteUser);
  1232. }
  1233. void CNmLDAP::_AddUser()
  1234. {
  1235. DBGENTRY(CNmLDAP::_AddUser);
  1236. TRACE_OUT(("CNmLDAP::_AddUser:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1237. ASSERT(NULL != m_pLdap);
  1238. ASSERT(Bound == m_State);
  1239. ASSERT(INVALID_MSG_ID == m_uMsgID);
  1240. // These are the user attribute values
  1241. DECLARE_LDAP_MOD(LDAP_MOD_ADD, cn, const_cast<LPTSTR>((LPCTSTR)m_strEmailName));
  1242. DECLARE_LDAP_MOD(LDAP_MOD_ADD, givenname, const_cast<LPTSTR>((LPCTSTR)m_strGivenName));
  1243. DECLARE_LDAP_MOD(LDAP_MOD_ADD, surname, const_cast<LPTSTR>((LPCTSTR)m_strSurName));
  1244. DECLARE_LDAP_MOD(LDAP_MOD_ADD, rfc822mailbox, const_cast<LPTSTR>((LPCTSTR)m_strEmailName));
  1245. DECLARE_LDAP_MOD(LDAP_MOD_ADD, location, const_cast<LPTSTR>((LPCTSTR)m_strLocation));
  1246. DECLARE_LDAP_MOD(LDAP_MOD_ADD, comment, const_cast<LPTSTR>((LPCTSTR)m_strComment));
  1247. DECLARE_LDAP_MOD(LDAP_MOD_ADD, sflags, m_bVisible ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
  1248. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA26214430, m_bInCall ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
  1249. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA32833566, m_bAudioHardware ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
  1250. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA32964638, m_bVideoHardware ? LDAP_ATTR_TRUE : LDAP_ATTR_FALSE );
  1251. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA39321630, LDAP_ATTR_BUSINESS );
  1252. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ssecurity, const_cast<LPTSTR>((LPCTSTR)m_strSecurityToken));
  1253. DECLARE_LDAP_MOD(LDAP_MOD_ADD, c, LDAP_ATTR_DUMMY_COUNTRYNAME);
  1254. // We have to get IP address dynamically
  1255. TCHAR szIpAddr[MAX_PATH];
  1256. szIpAddr[0] = _T('\0');
  1257. DWORD dwLocalIPAddress = INADDR_NONE;
  1258. _GetIpAddressOfLdapSession( szIpAddr, CCHMAX(szIpAddr), &dwLocalIPAddress );
  1259. DECLARE_LDAP_MOD(LDAP_MOD_ADD, sipaddress, szIpAddr);
  1260. // We store the version info on the server
  1261. TCHAR szVer[MAX_PATH];
  1262. wsprintf(szVer,"%lu",VER_PRODUCTVERSION_DW);
  1263. DECLARE_LDAP_MOD(LDAP_MOD_ADD, ilsA26279966, szVer);
  1264. // This is the user mod array
  1265. LDAPMod *apModUser[] =
  1266. {
  1267. LDAP_MOD_ENTRY(cn),
  1268. LDAP_MOD_ENTRY(givenname),
  1269. LDAP_MOD_ENTRY(surname),
  1270. LDAP_MOD_ENTRY(rfc822mailbox),
  1271. LDAP_MOD_ENTRY(location),
  1272. LDAP_MOD_ENTRY(comment),
  1273. LDAP_MOD_ENTRY(c),
  1274. LDAP_MOD_ENTRY(sipaddress),
  1275. LDAP_MOD_ENTRY(sflags),
  1276. LDAP_MOD_ENTRY(ssecurity),
  1277. LDAP_MOD_ENTRY(ilsA26214430),
  1278. LDAP_MOD_ENTRY(ilsA26279966),
  1279. LDAP_MOD_ENTRY(ilsA32833566),
  1280. LDAP_MOD_ENTRY(ilsA32964638),
  1281. LDAP_MOD_ENTRY(ilsA39321630),
  1282. NULL
  1283. };
  1284. TCHAR* szDN = new TCHAR[ lstrlen(LOGIN_USER_FILTER) + lstrlen(m_strEmailName) + 1 ];
  1285. if( szDN )
  1286. {
  1287. wsprintf(szDN, LOGIN_USER_FILTER, m_strEmailName);
  1288. m_strCurrentDN = szDN;
  1289. delete [] szDN;
  1290. }
  1291. TCHAR* szRefresh = new TCHAR[ lstrlen(LDAP_REFRESH_FILTER) + lstrlen(m_strEmailName) + 1 ];
  1292. if( szRefresh )
  1293. {
  1294. wsprintf(szRefresh, LDAP_REFRESH_FILTER, m_strEmailName);
  1295. }
  1296. m_uMsgID = WLDAP::ldap_add( m_pLdap, const_cast<LPTSTR>((LPCTSTR)m_strCurrentDN), apModUser );
  1297. if( INVALID_MSG_ID != m_uMsgID )
  1298. {
  1299. m_State = AddingUser;
  1300. m_ResultPollTimer = ::SetTimer( m_hWndHidden, PollForResultTimer, RESULT_POLL_INTERVAL, NULL );
  1301. ASSERT(m_ResultPollTimer);
  1302. // create the keep alive object
  1303. if (NULL != m_pKeepAlive)
  1304. {
  1305. m_pKeepAlive->End();
  1306. m_pKeepAlive = NULL;
  1307. }
  1308. BOOL fRet = FALSE;
  1309. m_pKeepAlive = new CKeepAlive(&fRet,
  1310. m_hWndHidden,
  1311. dwLocalIPAddress,
  1312. m_strCurrentServer, m_iPort,
  1313. szRefresh);
  1314. ASSERT(NULL != m_pKeepAlive && fRet);
  1315. }
  1316. else
  1317. {
  1318. WLDAP::ldap_unbind(m_pLdap);
  1319. m_pLdap = NULL;
  1320. m_State = Idle;
  1321. }
  1322. delete [] szRefresh;
  1323. SetLoggedOn( IsLoggedOn() );
  1324. TRACE_OUT(("CNmLDAP::_AddUser:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1325. DBGEXIT(CNmLDAP::_AddUser);
  1326. }
  1327. void CNmLDAP::_OnLoggedOn()
  1328. {
  1329. DBGENTRY(CNmLDAP::_OnLoggedOn);
  1330. TRACE_OUT(("CNmLDAP::_OnLoggedOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1331. ::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
  1332. TRACE_OUT(("CNmLDAP::_OnLoggedOn:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1333. DBGEXIT(CNmLDAP::_OnLoggedOn);
  1334. }
  1335. void CNmLDAP::_OnLoggedOff()
  1336. {
  1337. DBGENTRY(CNmLDAP::_OnLoggedOff);
  1338. TRACE_OUT(("CNmLDAP::_OnLoggedOff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1339. ::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
  1340. TRACE_OUT(("CNmLDAP::_OnLoggedOff:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1341. DBGEXIT(CNmLDAP::_OnLoggedOff);
  1342. }
  1343. void CNmLDAP::_OnLoggingOn()
  1344. {
  1345. DBGENTRY(CNmLDAP::_OnLoggingOn);
  1346. TRACE_OUT(("CNmLDAP::_OnLoggingOn:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1347. ::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
  1348. TRACE_OUT(("CNmLDAP::_OnLoggingOn:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1349. DBGEXIT(CNmLDAP::_OnLoggingOn);
  1350. }
  1351. void CNmLDAP::_OnLoggingOff()
  1352. {
  1353. DBGENTRY(CNmLDAP::_OnLoggingOff);
  1354. TRACE_OUT(("CNmLDAP::_OnLoggingOff:enter: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1355. ::UpdateUI(CRUI_STATUSBAR | CRUI_CALLANIM, TRUE);
  1356. TRACE_OUT(("CNmLDAP::_OnLoggingOff:exit: m_State:%d: m_currentOp:%d", m_State, m_CurrentOp));
  1357. DBGEXIT(CNmLDAP::_OnLoggingOff);
  1358. }
  1359. void CNmLDAP::_GetIpAddressOfLdapSession( LPTSTR szIpAddr, int cchMax, DWORD *pdwIPAddr )
  1360. {
  1361. DBGENTRY(CNmLDAP::_GetIpAddressOfLdapSession);
  1362. if (NULL != szIpAddr)
  1363. {
  1364. szIpAddr[0] = _T('\0');
  1365. }
  1366. SOCKET s = INVALID_SOCKET;
  1367. if( LDAP_SUCCESS == WLDAP::ldap_get_option(m_pLdap, LDAP_OPT_DESC, &s ))
  1368. {
  1369. SOCKADDR_IN addr;
  1370. int NameLen = sizeof(addr);
  1371. if(0 == getsockname(s, reinterpret_cast<SOCKADDR*>(&addr), &NameLen))
  1372. {
  1373. if (NULL != szIpAddr)
  1374. {
  1375. wsprintf(szIpAddr, "%u", addr.sin_addr.s_addr);
  1376. }
  1377. if (NULL != pdwIPAddr)
  1378. {
  1379. *pdwIPAddr = addr.sin_addr.s_addr;
  1380. }
  1381. }
  1382. }
  1383. DBGEXIT(CNmLDAP::_GetIpAddressOfLdapSession);
  1384. }
  1385. void InitNmLdapAndLogon()
  1386. {
  1387. ASSERT( NULL == g_pLDAP );
  1388. g_pLDAP = new CNmLDAP;
  1389. if(g_pLDAP)
  1390. {
  1391. // Initialize the LDAP object...
  1392. if( SUCCEEDED(g_pLDAP->Initialize( _Module.GetModuleInstance())))
  1393. {
  1394. g_pLDAP->LogonAsync();
  1395. }
  1396. else
  1397. {
  1398. delete g_pLDAP;
  1399. g_pLDAP = NULL;
  1400. }
  1401. }
  1402. else
  1403. {
  1404. ERROR_OUT(("new CNmLDAP returned NULL"));
  1405. }
  1406. }
  1407. /////////////////////////////////////////////////////////
  1408. //
  1409. // CKeepAlive
  1410. //
  1411. void CALLBACK KeepAliveTimerProc(HWND, UINT, UINT_PTR, DWORD)
  1412. {
  1413. // doing nothing at all
  1414. }
  1415. DWORD KeepAliveThreadProc(LPVOID pParam)
  1416. {
  1417. // make sure we have a valid socket
  1418. WSADATA wsaData;
  1419. int iRet = ::WSAStartup(0x0101, &wsaData);
  1420. ASSERT(! iRet);
  1421. if (! iRet)
  1422. {
  1423. CKeepAlive *pKeepAlive = (CKeepAlive *) pParam;
  1424. ASSERT(NULL != pKeepAlive);
  1425. // translate server name into ip address
  1426. if (pKeepAlive->SetServerIPAddress())
  1427. {
  1428. // start the timer
  1429. UINT nKeepAliveInterval = INITIAL_REFRESH_INTERVAL_MINUTES;
  1430. UINT_PTR nTimerID = ::SetTimer(NULL, 0, nKeepAliveInterval * 60 * 1000, KeepAliveTimerProc);
  1431. ASSERT(nTimerID);
  1432. // watch for the timer message
  1433. MSG msg, msg2;
  1434. while (::GetMessage(&msg, NULL, 0, 0))
  1435. {
  1436. msg2 = msg; // keep a copy of this message
  1437. // dispatch messages
  1438. ::DispatchMessage(&msg);
  1439. // intercept the WM_TIMER message thru msg2
  1440. if (WM_TIMER == msg2.message && nTimerID == msg2.wParam)
  1441. {
  1442. BOOL fRetry = TRUE;
  1443. // kill the timer to avoid timer overrun
  1444. ::KillTimer(NULL, nTimerID);
  1445. nTimerID = 0;
  1446. // ping the server in case of dialup networking
  1447. if (pKeepAlive->Ping())
  1448. {
  1449. // connect to the server
  1450. LDAP *ld = WLDAP::ldap_open(pKeepAlive->GetServerName(),
  1451. pKeepAlive->GetServerPortNumber());
  1452. if (NULL != ld)
  1453. {
  1454. if (pKeepAlive->Bind(ld))
  1455. {
  1456. if (pKeepAlive->KeepAlive(ld, &nKeepAliveInterval))
  1457. {
  1458. // successfully send a keep alive
  1459. fRetry = FALSE;
  1460. DWORD dwLocalIPAddress = pKeepAlive->GetLocalIPAddress(ld);
  1461. if (INADDR_NONE != dwLocalIPAddress)
  1462. {
  1463. if (pKeepAlive->GetLocalIPAddress() != dwLocalIPAddress)
  1464. {
  1465. pKeepAlive->SetLocalIPAddress(dwLocalIPAddress);
  1466. pKeepAlive->UpdateIPAddressOnServer();
  1467. }
  1468. }
  1469. }
  1470. }
  1471. WLDAP::ldap_unbind(ld);
  1472. }
  1473. }
  1474. // start the new timer based on the new internal
  1475. nTimerID = ::SetTimer(NULL, 0,
  1476. fRetry ? (15 * 1000) : (nKeepAliveInterval * 60 * 1000),
  1477. KeepAliveTimerProc);
  1478. ASSERT(nTimerID);
  1479. } // if wm timer
  1480. } // while get message
  1481. if (nTimerID)
  1482. {
  1483. ::KillTimer(NULL, nTimerID);
  1484. }
  1485. }
  1486. delete pKeepAlive;
  1487. ::WSACleanup();
  1488. }
  1489. return 0;
  1490. }
  1491. CKeepAlive::CKeepAlive
  1492. (
  1493. BOOL *pfRet,
  1494. HWND hwndMainThread,
  1495. DWORD dwLocalIPAddress,
  1496. const TCHAR * const pcszServerName,
  1497. UINT nPort,
  1498. LPTSTR pszKeepAliveFilter
  1499. )
  1500. :
  1501. m_hwndMainThread(hwndMainThread),
  1502. m_dwLocalIPAddress(dwLocalIPAddress),
  1503. m_dwServerIPAddress(INADDR_NONE),
  1504. m_pszServerName(NULL),
  1505. m_nPort(nPort),
  1506. m_pszKeepAliveFilter(NULL),
  1507. m_hThread(NULL),
  1508. m_dwThreadID(0),
  1509. m_fAborted(FALSE)
  1510. {
  1511. *pfRet = FALSE; // assume failure
  1512. // sanity check
  1513. ASSERT(NULL != hwndMainThread);
  1514. ASSERT(INADDR_NONE != dwLocalIPAddress && 0 != dwLocalIPAddress);
  1515. ASSERT(nPort);
  1516. // create the server name
  1517. ASSERT(NULL != pcszServerName);
  1518. ULONG nStrLen = ::lstrlen(pcszServerName) + 1;
  1519. m_pszServerName = new TCHAR[nStrLen];
  1520. if (NULL != m_pszServerName)
  1521. {
  1522. ::CopyMemory(m_pszServerName, pcszServerName, nStrLen * sizeof(TCHAR));
  1523. TCHAR * const pszPort = StrChr( m_pszServerName, ':' );
  1524. if( pszPort != NULL )
  1525. {
  1526. // Truncate the server name here for dns lookup....
  1527. // and this port number overrides the nPort parameter...
  1528. *pszPort = '\0';
  1529. HRESULT hrResult = DecimalStringToUINT( pszPort + 1, m_nPort );
  1530. ASSERT( hrResult == S_OK );
  1531. if( hrResult != S_OK )
  1532. {
  1533. m_nPort = DEFAULT_LDAP_PORT;
  1534. }
  1535. }
  1536. // create the fresh filter
  1537. ASSERT(NULL != pszKeepAliveFilter);
  1538. nStrLen = ::lstrlen(pszKeepAliveFilter) + 1;
  1539. m_pszKeepAliveFilter = new TCHAR[nStrLen];
  1540. if (NULL != m_pszKeepAliveFilter)
  1541. {
  1542. ::CopyMemory(m_pszKeepAliveFilter, pszKeepAliveFilter, nStrLen * sizeof(TCHAR));
  1543. *pfRet = TRUE;
  1544. }
  1545. }
  1546. }
  1547. CKeepAlive::~CKeepAlive(void)
  1548. {
  1549. delete m_pszServerName;
  1550. delete m_pszKeepAliveFilter;
  1551. }
  1552. BOOL CKeepAlive::Start(void)
  1553. {
  1554. if (! m_dwThreadID)
  1555. {
  1556. ASSERT(NULL == m_hThread);
  1557. // create the worker thread
  1558. m_hThread = ::CreateThread(NULL, 0, KeepAliveThreadProc, this, 0, &m_dwThreadID);
  1559. }
  1560. ASSERT(NULL != m_hThread);
  1561. return (NULL != m_hThread);
  1562. }
  1563. BOOL CKeepAlive::End(BOOL fSync)
  1564. {
  1565. DWORD dwRet = WAIT_OBJECT_0;
  1566. // cache thread handle and ID
  1567. HANDLE hThread = m_hThread;
  1568. DWORD dwThreadID = m_dwThreadID;
  1569. // abort any pending operation
  1570. m_fAborted = TRUE;
  1571. // notify the worker thread to go away
  1572. if (m_dwThreadID)
  1573. {
  1574. ASSERT(NULL != m_hThread);
  1575. m_dwThreadID = 0;
  1576. ::PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  1577. }
  1578. // wait for the worker thread exit for 5 seconds
  1579. if (NULL != hThread)
  1580. {
  1581. // need more work to unblock it
  1582. if (fSync)
  1583. {
  1584. dwRet = ::WaitForSingleObject(hThread, 5000); // 5 second timeout
  1585. ASSERT(WAIT_TIMEOUT != dwRet);
  1586. }
  1587. ::CloseHandle(hThread);
  1588. }
  1589. return (WAIT_TIMEOUT != dwRet);
  1590. }
  1591. BOOL CKeepAlive::SetServerIPAddress(void)
  1592. {
  1593. ASSERT(NULL != m_pszServerName);
  1594. // check to see if the server name is a dotted IP address string
  1595. m_dwServerIPAddress = ::inet_addr(m_pszServerName);
  1596. if (INADDR_NONE == m_dwServerIPAddress)
  1597. {
  1598. // it is not a dotted string, it must be a name.
  1599. // get the host entry by name
  1600. PHOSTENT phe = ::gethostbyname(m_pszServerName);
  1601. if (phe != NULL)
  1602. {
  1603. // get info from the host entry
  1604. m_dwServerIPAddress = *(DWORD *) phe->h_addr;
  1605. }
  1606. }
  1607. ASSERT(INADDR_NONE != m_dwServerIPAddress);
  1608. return (INADDR_NONE != m_dwServerIPAddress);
  1609. }
  1610. BOOL CKeepAlive::Ping(void)
  1611. {
  1612. BOOL fRet = TRUE; // assume success
  1613. if (NULL != g_pPing)
  1614. {
  1615. if (g_pPing->IsAutodialEnabled())
  1616. {
  1617. ASSERT(INADDR_NONE != m_dwServerIPAddress);
  1618. HRESULT hr = g_pPing->Ping(m_dwServerIPAddress, PING_TIMEOUT_INTERVAL, PING_RETRIES);
  1619. fRet = (S_OK == hr);
  1620. }
  1621. }
  1622. return fRet;
  1623. }
  1624. BOOL CKeepAlive::Bind(LDAP *ld)
  1625. {
  1626. ASSERT(NULL != ld);
  1627. if (! m_fAborted)
  1628. {
  1629. // anonymous bind
  1630. ULONG nMsgID = WLDAP::ldap_bind(ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
  1631. if (INVALID_MSG_ID != nMsgID)
  1632. {
  1633. // poll the result every quarter second
  1634. const ULONG c_nTimeoutInQuarterSecond = 4 * LDAP_TIMEOUT_IN_SECONDS;
  1635. for (ULONG i = 0; (i < c_nTimeoutInQuarterSecond) && (! m_fAborted); i++)
  1636. {
  1637. // no timeout, if no result, return immediately
  1638. LDAP_TIMEVAL TimeVal;
  1639. TimeVal.tv_usec = 0;
  1640. TimeVal.tv_sec = 0;
  1641. // check the result
  1642. LDAPMessage *pMsg = NULL;
  1643. ULONG nResultType = WLDAP::ldap_result(ld, nMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
  1644. if (nResultType == LDAP_RES_BIND)
  1645. {
  1646. ASSERT(NULL != pMsg);
  1647. WLDAP::ldap_msgfree(pMsg);
  1648. return TRUE;
  1649. }
  1650. // deal with timeout or error
  1651. if (LDAP_RESULT_TIMEOUT == nResultType)
  1652. {
  1653. if (! m_fAborted)
  1654. {
  1655. ::Sleep(250); // sleep for a quarter second
  1656. continue;
  1657. }
  1658. }
  1659. ASSERT(LDAP_RESULT_ERROR != nResultType);
  1660. break;
  1661. }
  1662. // failure, do the cleanup
  1663. WLDAP::ldap_abandon(ld, nMsgID);
  1664. }
  1665. }
  1666. return FALSE;
  1667. }
  1668. DWORD CKeepAlive::GetLocalIPAddress(LDAP *ld)
  1669. {
  1670. SOCKET s = INVALID_SOCKET;
  1671. if (LDAP_SUCCESS == WLDAP::ldap_get_option(ld, LDAP_OPT_DESC, &s))
  1672. {
  1673. SOCKADDR_IN addr;
  1674. int NameLen = sizeof(addr);
  1675. if (0 == ::getsockname(s, (SOCKADDR *) &addr, &NameLen))
  1676. {
  1677. return addr.sin_addr.s_addr;
  1678. }
  1679. }
  1680. return INADDR_NONE;
  1681. }
  1682. BOOL CKeepAlive::KeepAlive(LDAP *ld, UINT *pnKeepAliveInterval)
  1683. {
  1684. LPTSTR aTTLAttr[] = { STTL_ATTR_NAME, NULL };
  1685. UINT nMsgID = WLDAP::ldap_search(ld,
  1686. LDAP_REFRESH_BASE_DN,
  1687. LDAP_SCOPE_BASE,
  1688. m_pszKeepAliveFilter,
  1689. aTTLAttr,
  1690. FALSE);
  1691. if (INVALID_MSG_ID != nMsgID)
  1692. {
  1693. // poll the result every quarter second
  1694. const ULONG c_nTimeoutInQuarterSecond = 4 * LDAP_TIMEOUT_IN_SECONDS;
  1695. BOOL fError = FALSE;
  1696. for (ULONG i = 0; (i < c_nTimeoutInQuarterSecond) && (! m_fAborted) && (! fError); i++)
  1697. {
  1698. // no timeout, if no result, return immediately
  1699. LDAP_TIMEVAL TimeVal;
  1700. TimeVal.tv_usec = 0;
  1701. TimeVal.tv_sec = 0;
  1702. // check the result
  1703. LDAPMessage *pMsg = NULL;
  1704. ULONG nResultType = WLDAP::ldap_result(ld, nMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
  1705. switch (nResultType)
  1706. {
  1707. case LDAP_RESULT_TIMEOUT:
  1708. if (! m_fAborted)
  1709. {
  1710. ::Sleep(250); // sleep for a quarter second
  1711. }
  1712. break;
  1713. case LDAP_RESULT_ERROR:
  1714. fError = TRUE;
  1715. break;
  1716. default:
  1717. ASSERT(LDAP_RES_SEARCH_ENTRY == nResultType ||
  1718. LDAP_RES_SEARCH_RESULT == nResultType);
  1719. ASSERT(NULL != pMsg);
  1720. switch (pMsg->lm_returncode)
  1721. {
  1722. case LDAP_SUCCESS:
  1723. GetNewInterval(ld, pMsg, pnKeepAliveInterval);
  1724. break;
  1725. case LDAP_NO_SUCH_OBJECT:
  1726. ReLogon();
  1727. fError = TRUE;
  1728. break;
  1729. default:
  1730. break;
  1731. }
  1732. WLDAP::ldap_msgfree(pMsg);
  1733. return (! fError);
  1734. }
  1735. }
  1736. // failure, do the cleanup
  1737. WLDAP::ldap_abandon(ld, nMsgID);
  1738. }
  1739. return FALSE;
  1740. }
  1741. void CKeepAlive::GetNewInterval(LDAP *ld, LDAPMessage *pMsg, UINT *pnKeepAliveInterval)
  1742. {
  1743. // get the first entry which should contain the new ttl value
  1744. LDAPMessage *pEntry = WLDAP::ldap_first_entry(ld, pMsg);
  1745. if (NULL != pEntry)
  1746. {
  1747. // get the first attribute which should be the new ttl value
  1748. BerElement *pElement = NULL;
  1749. LPTSTR pszAttrib = WLDAP::ldap_first_attribute(ld, pEntry, &pElement);
  1750. if (NULL != pszAttrib)
  1751. {
  1752. // it should be ttl attribute
  1753. ASSERT(! lstrcmpi(STTL_ATTR_NAME, pszAttrib));
  1754. // get the value
  1755. LPTSTR *ppszTTL = WLDAP::ldap_get_values(ld, pEntry, pszAttrib);
  1756. if (NULL != ppszTTL)
  1757. {
  1758. if (NULL != ppszTTL[0])
  1759. {
  1760. int iRefresh = ::RtStrToInt(ppszTTL[0]) - REFRESH_TIMEOUT_MARGIN;
  1761. if (iRefresh > 0)
  1762. {
  1763. if (iRefresh < MIN_REFRESH_TIMEOUT_INTERVAL_MINUTES)
  1764. {
  1765. iRefresh = MIN_REFRESH_TIMEOUT_INTERVAL_MINUTES;
  1766. }
  1767. *pnKeepAliveInterval = (UINT) iRefresh;
  1768. }
  1769. }
  1770. WLDAP::ldap_value_free(ppszTTL);
  1771. }
  1772. }
  1773. }
  1774. }
  1775. void CKeepAlive::ReLogon(void)
  1776. {
  1777. ::PostMessage(m_hwndMainThread, WM_NEED_RELOGON, 0, 0);
  1778. }
  1779. void CKeepAlive::UpdateIPAddressOnServer(void)
  1780. {
  1781. ::PostMessage(m_hwndMainThread, WM_NEED_RELOGON, 0, 0);
  1782. }
  1783. /////////////////////////////////////////////////////////
  1784. //
  1785. // ResolveUser
  1786. //
  1787. typedef struct tagResolveInfo
  1788. {
  1789. // given
  1790. DWORD cchMax;
  1791. LPTSTR pszIPAddress;
  1792. // created
  1793. LPTSTR pszSearchFilter;
  1794. LDAP *ld;
  1795. }
  1796. RESOLVE_INFO;
  1797. void FreeResolveInfo(RESOLVE_INFO *pInfo)
  1798. {
  1799. if (NULL != pInfo)
  1800. {
  1801. delete pInfo->pszSearchFilter;
  1802. if (NULL != pInfo->ld)
  1803. {
  1804. WLDAP::ldap_unbind(pInfo->ld);
  1805. }
  1806. delete pInfo;
  1807. }
  1808. }
  1809. DWORD ResolveUserThreadProc(LPVOID pParam)
  1810. {
  1811. RESOLVE_INFO *pInfo = (RESOLVE_INFO *) pParam;
  1812. ASSERT(NULL != pInfo);
  1813. // send the search request
  1814. TCHAR* attrs[] = { IP_ADDRESS_ATTR_NAME, NULL };
  1815. ULONG nMsgID = WLDAP::ldap_search(pInfo->ld,
  1816. TEXT("objectClass=RTPerson"),
  1817. LDAP_SCOPE_BASE,
  1818. pInfo->pszSearchFilter,
  1819. attrs,
  1820. 0);
  1821. if (INVALID_MSG_ID != nMsgID)
  1822. {
  1823. LDAPMessage *pMsg = NULL;
  1824. LDAP_TIMEVAL SearchTimeout = { LDAP_TIMEOUT_IN_SECONDS, 0 };
  1825. ULONG nResultType = WLDAP::ldap_result(pInfo->ld,
  1826. nMsgID,
  1827. LDAP_MSG_ALL,
  1828. &SearchTimeout,
  1829. &pMsg);
  1830. switch (nResultType)
  1831. {
  1832. case LDAP_RESULT_TIMEOUT:
  1833. case LDAP_RESULT_ERROR:
  1834. WLDAP::ldap_abandon(pInfo->ld, nMsgID);
  1835. break;
  1836. default:
  1837. {
  1838. ASSERT(LDAP_RES_SEARCH_ENTRY == nResultType ||
  1839. LDAP_RES_SEARCH_RESULT == nResultType);
  1840. ASSERT(NULL != pMsg);
  1841. // get the first entry
  1842. LDAPMessage *pEntry = WLDAP::ldap_first_entry(pInfo->ld, pMsg);
  1843. if (NULL != pEntry)
  1844. {
  1845. BerElement *pElement = NULL;
  1846. // get the first attribute
  1847. LPTSTR pszAttrib = WLDAP::ldap_first_attribute(pInfo->ld, pEntry, &pElement);
  1848. if (NULL != pszAttrib)
  1849. {
  1850. ASSERT(! lstrcmpi(IP_ADDRESS_ATTR_NAME, pszAttrib));
  1851. // get the value
  1852. LPTSTR *ppszIPAddress = WLDAP::ldap_get_values(pInfo->ld, pEntry, pszAttrib);
  1853. if (NULL != ppszIPAddress)
  1854. {
  1855. if (NULL != ppszIPAddress[0])
  1856. {
  1857. BYTE temp[sizeof(DWORD)];
  1858. *(DWORD *) &temp[0] = ::RtStrToInt(ppszIPAddress[0]);
  1859. ::wsprintf(pInfo->pszIPAddress, TEXT("%u.%u.%u.%u"),
  1860. (UINT) temp[0], (UINT) temp[1],
  1861. (UINT) temp[2], (UINT) temp[3]);
  1862. }
  1863. WLDAP::ldap_value_free(ppszIPAddress);
  1864. }
  1865. } // if attribute
  1866. } // if entry
  1867. WLDAP::ldap_msgfree(pMsg);
  1868. }
  1869. break;
  1870. } // switch
  1871. } // if msg id
  1872. return 0;
  1873. }
  1874. /*static*/
  1875. HRESULT CNmLDAP::ResolveUser( LPCTSTR pcszName, LPCTSTR pcszServer, LPTSTR pszIPAddress, DWORD cchMax, int port )
  1876. {
  1877. HRESULT hr = E_OUTOFMEMORY;
  1878. RESOLVE_INFO *pInfo = NULL;
  1879. // clean up the return buffer
  1880. *pszIPAddress = TEXT('\0');
  1881. // make sure the wldap32.dll is loaded
  1882. if( ms_bLdapDLLLoaded || SUCCEEDED( hr = WLDAP::Init()))
  1883. {
  1884. ms_bLdapDLLLoaded = true;
  1885. // create a resolve info which exchanges info between this thread and a background thread.
  1886. pInfo = new RESOLVE_INFO;
  1887. if (NULL != pInfo)
  1888. {
  1889. // cleanup
  1890. ::ZeroMemory(pInfo, sizeof(*pInfo));
  1891. // remember return buffer and its size
  1892. pInfo->pszIPAddress = pszIPAddress;
  1893. pInfo->cchMax = cchMax;
  1894. // create search filter
  1895. ULONG cbFilterSize = ::lstrlen(RESOLVE_USER_SEARCH_FILTER) + ::lstrlen(pcszName) + 2;
  1896. pInfo->pszSearchFilter = new TCHAR[cbFilterSize];
  1897. if (NULL != pInfo->pszSearchFilter)
  1898. {
  1899. // construct search filter
  1900. ::wsprintf(pInfo->pszSearchFilter, RESOLVE_USER_SEARCH_FILTER, pcszName);
  1901. // create ldap block that is NOT connected to server yet.
  1902. pInfo->ld = WLDAP::ldap_init(const_cast<LPTSTR>(pcszServer), port);
  1903. if( pInfo->ld != NULL )
  1904. {
  1905. ULONG ulResult = WLDAP::ldap_bind_s(pInfo->ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
  1906. if( (ulResult != LDAP_SUCCESS) && (port == DEFAULT_LDAP_PORT) )
  1907. {
  1908. WLDAP::ldap_unbind(pInfo->ld);
  1909. pInfo->ld = WLDAP::ldap_init(const_cast<LPTSTR>(pcszServer), ALTERNATE_LDAP_PORT); // Automatically retry with alternate port...
  1910. if( pInfo->ld != NULL )
  1911. {
  1912. ulResult = WLDAP::ldap_bind_s(pInfo->ld, TEXT(""), TEXT(""), LDAP_AUTH_SIMPLE);
  1913. if( ulResult != LDAP_SUCCESS )
  1914. {
  1915. WLDAP::ldap_unbind(pInfo->ld);
  1916. pInfo->ld = NULL;
  1917. }
  1918. }
  1919. }
  1920. }
  1921. ASSERT(NULL != pInfo->ld);
  1922. if (NULL != pInfo->ld)
  1923. {
  1924. DWORD dwThreadID = 0;
  1925. HANDLE hThread = ::CreateThread(NULL, 0, ResolveUserThreadProc, pInfo, 0, &dwThreadID);
  1926. if (NULL != hThread)
  1927. {
  1928. // wait for the thread to exit
  1929. hr = ::WaitWithMessageLoop(hThread);
  1930. DWORD dwIPAddr = ::inet_addr(pszIPAddress);
  1931. hr = (dwIPAddr && INADDR_NONE != dwIPAddr) ? S_OK : E_FAIL;
  1932. // close thread
  1933. ::CloseHandle(hThread);
  1934. }
  1935. } // if ld
  1936. } // if search filter
  1937. } // if new resolve info
  1938. } // if init
  1939. ::FreeResolveInfo(pInfo);
  1940. return hr;
  1941. }
  1942.