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.

243 lines
6.9 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: dbconn.cxx
  7. //
  8. // Contents: Shared database initialization code.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. //
  15. //
  16. // History: 18-Nov-96 BillMo Created.
  17. //
  18. // Notes:
  19. //
  20. // Codework:
  21. //
  22. //--------------------------------------------------------------------------
  23. #include "pch.cxx"
  24. #pragma hdrstop
  25. #include "trksvr.hxx"
  26. // LDAP version
  27. void
  28. CDbConnection::Initialize(CSvcCtrlInterface * psvc, OPTIONAL const TCHAR *ptszHostName )
  29. {
  30. int err;
  31. LDAPMessage *pRes = NULL;
  32. TCHAR ** ppszNamingContexts = NULL;
  33. int tries = 0;
  34. TCHAR tszLocalHostName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  35. _fInitializeCalled = TRUE;
  36. _pszBaseDn = NULL;
  37. __try
  38. {
  39. if( NULL == ptszHostName )
  40. {
  41. CMachineId(MCID_LOCAL).GetName( tszLocalHostName, ELEMENTS(tszLocalHostName) );
  42. ptszHostName = tszLocalHostName;
  43. }
  44. TrkLog((TRKDBG_SVR, TEXT("ldap_init(%s, LDAP_PORT)"), ptszHostName ));
  45. _pldap = ldap_init( const_cast<TCHAR*>(ptszHostName), LDAP_PORT);
  46. if( NULL == _pldap )
  47. {
  48. TrkLog(( TRKDBG_ERROR, TEXT("CDbConnection failed ldap_init (%lu)"),
  49. GetLastError() ));
  50. TrkRaiseLastError();
  51. }
  52. // Set the option telling LDAP that we gave it an explicit DC name and
  53. // that it can avoid the DsGetDcName.
  54. LONG LdapOption = PtrToLong(LDAP_OPT_ON);
  55. err = ldap_set_optionW( _pldap, LDAP_OPT_AREC_EXCLUSIVE, &LdapOption );
  56. if( LDAP_SUCCESS != err )
  57. {
  58. TrkLog(( TRKDBG_ERROR,
  59. TEXT("Failed ldap_set_option (LDAP_OPT_AREC_EXCLUSIVE) - %ld"),
  60. err ));
  61. TrkRaiseException( LdapMapErrorToWin32(err) );
  62. }
  63. // Note: This method used to do an ldap_open, but that function has been
  64. // deprecated. The problem in NT5, was that during bootup call to ldap_open
  65. // the DS occasionally wasn't yet available. Thus the logic below was added
  66. // to do retries.
  67. // Really, all of this code should go away except for the ldap_init, since
  68. // ldap_connect is called implicitely by all the ldap apis. But to minimize
  69. // the risk, the code has been left basically unchanged, other than using
  70. // ldap_init/ldap_connect rather than ldap_open. If this code needs to be
  71. // modified at any point, it should be reworked to remove the ldap_connect.
  72. LDAP_TIMEVAL Timeout;
  73. Timeout.tv_sec = 2;
  74. Timeout.tv_usec = 0;
  75. retry:
  76. err = ldap_connect( _pldap, &Timeout );
  77. if( LDAP_SUCCESS != err )
  78. {
  79. if (tries++ < 10)
  80. {
  81. TrkLog((TRKDBG_ERROR, TEXT("ldap_open returned NULL, now sleeping...")));
  82. if (psvc != NULL)
  83. psvc->UpdateWaitHint(30000);
  84. goto retry;
  85. }
  86. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - failed :-(")));
  87. TrkRaiseLastError( );
  88. }
  89. // search to get default base DN
  90. err = ldap_bind_s(_pldap,
  91. NULL, // DN of what ? system account object ?
  92. NULL, // we're running as system, so use our credentials
  93. LDAP_AUTH_SSPI);
  94. if (err != LDAP_SUCCESS)
  95. {
  96. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_bind_s failed")));
  97. TrkRaiseWin32Error( LdapMapErrorToWin32(err) );
  98. }
  99. TCHAR *aszNamingContexts[2] = { TEXT("NamingContexts"), NULL };
  100. err = ldap_search_s(_pldap,
  101. NULL, // searching of tree
  102. LDAP_SCOPE_BASE,
  103. TEXT("(objectclass=*)"),
  104. aszNamingContexts,
  105. 0,
  106. &pRes);
  107. if (err != LDAP_SUCCESS)
  108. {
  109. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_search_s failed (%lu)"), err ));
  110. TrkRaiseException( TRK_E_DB_CONNECT_ERROR );
  111. }
  112. if (ldap_count_entries(_pldap, pRes) == 0)
  113. {
  114. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_count_entries found no entries (%lu)"), err ));
  115. TrkRaiseException( TRK_E_DB_CONNECT_ERROR );
  116. }
  117. LDAPMessage * pEntry = ldap_first_entry(_pldap, pRes);
  118. if (pEntry == NULL)
  119. {
  120. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_first_entry failed (%lu)"), err ));
  121. TrkRaiseWin32Error(LdapMapErrorToWin32(_pldap->ld_errno));
  122. }
  123. int l;
  124. ppszNamingContexts = ldap_get_values(_pldap, pEntry, TEXT("NamingContexts"));
  125. if (ppszNamingContexts == NULL ||
  126. ppszNamingContexts[0] == NULL ||
  127. (l=_tcslen(ppszNamingContexts[0])) == 0)
  128. {
  129. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - couldn't find 'NamingContexts'")));
  130. TrkRaiseWin32Error(LdapMapErrorToWin32(_pldap->ld_errno));
  131. }
  132. for (int i=0; i<l-4; i++)
  133. {
  134. if (memcmp(&ppszNamingContexts[0][i],
  135. TEXT("DC="),
  136. 3*sizeof(TCHAR)) == 0)
  137. {
  138. break;
  139. }
  140. }
  141. if (i == l-3)
  142. {
  143. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - couldn't find 'DC'")));
  144. TrkRaiseException( TRK_E_DB_CONNECT_ERROR );
  145. }
  146. _pszBaseDn = new TCHAR [l-i+1];
  147. if (_pszBaseDn == NULL)
  148. {
  149. TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - out of memory")));
  150. TrkRaiseWin32Error(ERROR_NOT_ENOUGH_MEMORY);
  151. }
  152. _tcscpy(_pszBaseDn, &ppszNamingContexts[0][i]);
  153. }
  154. __finally
  155. {
  156. if (pRes)
  157. ldap_msgfree(pRes);
  158. if (ppszNamingContexts)
  159. ldap_value_free(ppszNamingContexts);
  160. }
  161. }
  162. void
  163. CDbConnection::UnInitialize()
  164. {
  165. if (_fInitializeCalled)
  166. {
  167. if (_pldap != NULL)
  168. {
  169. // There is no ldap_close. Call ldap_unbind, even if ldap_bind
  170. // wasn't called.
  171. ldap_unbind( _pldap );
  172. _pldap = NULL;
  173. }
  174. if (_pszBaseDn)
  175. {
  176. delete [] _pszBaseDn;
  177. _pszBaseDn = NULL;
  178. }
  179. _fInitializeCalled = FALSE;
  180. }
  181. }
  182. LDAP *
  183. CDbConnection::Ldap()
  184. {
  185. // The critsec initialization may have failed.
  186. if( !_cs.IsInitialized() )
  187. _cs.Initialize(); // Raises on error
  188. _cs.Enter();
  189. if (!_fInitializeCalled)
  190. {
  191. __try
  192. {
  193. Initialize(NULL);
  194. }
  195. __finally
  196. {
  197. if (AbnormalTermination())
  198. {
  199. UnInitialize();
  200. _cs.Leave();
  201. }
  202. }
  203. }
  204. _cs.Leave();
  205. return(_pldap);
  206. }