// Copyright (c) 1996-1999 Microsoft Corporation //+------------------------------------------------------------------------- // // Microsoft Windows // // File: dbconn.cxx // // Contents: Shared database initialization code. // // Classes: // // Functions: // // // // History: 18-Nov-96 BillMo Created. // // Notes: // // Codework: // //-------------------------------------------------------------------------- #include "pch.cxx" #pragma hdrstop #include "trksvr.hxx" // LDAP version void CDbConnection::Initialize(CSvcCtrlInterface * psvc, OPTIONAL const TCHAR *ptszHostName ) { int err; LDAPMessage *pRes = NULL; TCHAR ** ppszNamingContexts = NULL; int tries = 0; TCHAR tszLocalHostName[ MAX_COMPUTERNAME_LENGTH + 1 ]; _fInitializeCalled = TRUE; _pszBaseDn = NULL; __try { if( NULL == ptszHostName ) { CMachineId(MCID_LOCAL).GetName( tszLocalHostName, ELEMENTS(tszLocalHostName) ); ptszHostName = tszLocalHostName; } TrkLog((TRKDBG_SVR, TEXT("ldap_init(%s, LDAP_PORT)"), ptszHostName )); _pldap = ldap_init( const_cast(ptszHostName), LDAP_PORT); if( NULL == _pldap ) { TrkLog(( TRKDBG_ERROR, TEXT("CDbConnection failed ldap_init (%lu)"), GetLastError() )); TrkRaiseLastError(); } // Set the option telling LDAP that we gave it an explicit DC name and // that it can avoid the DsGetDcName. LONG LdapOption = PtrToLong(LDAP_OPT_ON); err = ldap_set_optionW( _pldap, LDAP_OPT_AREC_EXCLUSIVE, &LdapOption ); if( LDAP_SUCCESS != err ) { TrkLog(( TRKDBG_ERROR, TEXT("Failed ldap_set_option (LDAP_OPT_AREC_EXCLUSIVE) - %ld"), err )); TrkRaiseException( LdapMapErrorToWin32(err) ); } // Note: This method used to do an ldap_open, but that function has been // deprecated. The problem in NT5, was that during bootup call to ldap_open // the DS occasionally wasn't yet available. Thus the logic below was added // to do retries. // Really, all of this code should go away except for the ldap_init, since // ldap_connect is called implicitely by all the ldap apis. But to minimize // the risk, the code has been left basically unchanged, other than using // ldap_init/ldap_connect rather than ldap_open. If this code needs to be // modified at any point, it should be reworked to remove the ldap_connect. LDAP_TIMEVAL Timeout; Timeout.tv_sec = 2; Timeout.tv_usec = 0; retry: err = ldap_connect( _pldap, &Timeout ); if( LDAP_SUCCESS != err ) { if (tries++ < 10) { TrkLog((TRKDBG_ERROR, TEXT("ldap_open returned NULL, now sleeping..."))); if (psvc != NULL) psvc->UpdateWaitHint(30000); goto retry; } TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - failed :-("))); TrkRaiseLastError( ); } // search to get default base DN err = ldap_bind_s(_pldap, NULL, // DN of what ? system account object ? NULL, // we're running as system, so use our credentials LDAP_AUTH_SSPI); if (err != LDAP_SUCCESS) { TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_bind_s failed"))); TrkRaiseWin32Error( LdapMapErrorToWin32(err) ); } TCHAR *aszNamingContexts[2] = { TEXT("NamingContexts"), NULL }; err = ldap_search_s(_pldap, NULL, // searching of tree LDAP_SCOPE_BASE, TEXT("(objectclass=*)"), aszNamingContexts, 0, &pRes); if (err != LDAP_SUCCESS) { TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_search_s failed (%lu)"), err )); TrkRaiseException( TRK_E_DB_CONNECT_ERROR ); } if (ldap_count_entries(_pldap, pRes) == 0) { TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_count_entries found no entries (%lu)"), err )); TrkRaiseException( TRK_E_DB_CONNECT_ERROR ); } LDAPMessage * pEntry = ldap_first_entry(_pldap, pRes); if (pEntry == NULL) { TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - ldap_first_entry failed (%lu)"), err )); TrkRaiseWin32Error(LdapMapErrorToWin32(_pldap->ld_errno)); } int l; ppszNamingContexts = ldap_get_values(_pldap, pEntry, TEXT("NamingContexts")); if (ppszNamingContexts == NULL || ppszNamingContexts[0] == NULL || (l=_tcslen(ppszNamingContexts[0])) == 0) { TrkLog((TRKDBG_ERROR, TEXT("CDbConnection::Initialize() - couldn't find 'NamingContexts'"))); TrkRaiseWin32Error(LdapMapErrorToWin32(_pldap->ld_errno)); } for (int i=0; i