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.

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