/* * Brutus source file for the BrutusLogOn servant. * Copyright (C) 2004 OMC Denmark ApS. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #define MAPIGUID_H // do not include mapiguid.h #include // MAPI_ALLOW_OTHERS is ignored due to security concerns // MAPI_NEW_SESSION is forced due to security concerns // All UI related flags are ignored // MAPI_FORCE_DOWNLOAD is ignored. Unclear how it should be interpreted static inline FLAGS native_logon_flags(const ::BRUTUS::BDEFINE Flags) { ::BRUTUS::BDEFINE flags = Flags; FLAGS retval = 0; retval |= MAPI_EXTENDED; retval |= MAPI_NT_SERVICE; retval |= MAPI_NEW_SESSION; if (flags & ::BRUTUS::BRUTUS_UNIQUE_SESSION) // ignore this flag here FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_UNIQUE_SESSION); if (flags & ::BRUTUS::BRUTUS_MAPI_NO_MAIL) { retval |= MAPI_NO_MAIL; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_NO_MAIL); } if (flags & ::BRUTUS::BRUTUS_MAPI_DEFAULT_SERVICES) { retval |= MAPI_DEFAULT_SERVICES; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_DEFAULT_SERVICES); } if (flags & ::BRUTUS::BRUTUS_MAPI_TIMEOUT_SHORT) { retval |= MAPI_TIMEOUT_SHORT; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_TIMEOUT_SHORT); } if (flags & ::BRUTUS::BRUTUS_MAPI_USE_DEFAULT) { retval |= MAPI_USE_DEFAULT; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_USE_DEFAULT); } if (flags & ::BRUTUS::BRUTUS_MAPI_EXPLICIT_PROFILE) { retval |= MAPI_EXPLICIT_PROFILE; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_EXPLICIT_PROFILE); } if (flags & ::BRUTUS::BRUTUS_MAPI_BG_SESSION) { retval |= MAPI_BG_SESSION; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_BG_SESSION); } // Must(?) fix handling of Unicode characters if (flags & ::BRUTUS::BRUTUS_MAPI_UNICODE) { retval |= MAPI_UNICODE; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_UNICODE); } if (flags) { char msg[128] = {0}; sprintf_s(msg, sizeof(msg), "Unknown or unsupported flag(s) from BRUTUS : %X", flags); BRUTUS_LOG_BUG(msg); } return retval; } static inline FLAGS native_create_profile_flags(const ::BRUTUS::BDEFINE Flags) { ::BRUTUS::BDEFINE flags = Flags; FLAGS retval = 0; if (flags & ::BRUTUS::BRUTUS_MAPI_DEFAULT_SERVICES) { retval |= MAPI_DEFAULT_SERVICES; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_DEFAULT_SERVICES); } // Must(?) fix handling of Unicode characters if (flags & ::BRUTUS::BRUTUS_MAPI_UNICODE) { retval |= MAPI_UNICODE; FLAGS_OFF(::BRUTUS::BDEFINE, flags, ::BRUTUS::BRUTUS_MAPI_UNICODE); } if (flags) { char msg[128] = {0}; sprintf_s(msg, sizeof(msg), "Unknown or unsupported flag(s) from BRUTUS : %X", flags); BRUTUS_LOG_BUG(msg); } return retval; } static inline const char *spawn_status_msg(const ::BRUTUS::ProxyManager::SpawnStatus spawn_status) { switch (spawn_status) { case ::BRUTUS::ProxyManager::spawn_error_authentication : return "Spawn failure: spawn_error_authentication"; break; case ::BRUTUS::ProxyManager::spawn_error_mapi_logon : return "Spawn failure: spawn_error_mapi_logon"; break; case ::BRUTUS::ProxyManager::spawn_error_mapi_no_profile : return "Spawn failure: spawn_error_mapi_no_profile"; break; case ::BRUTUS::ProxyManager::spawn_error_lifeline : return "Spawn failure: spawn_error_lifeline"; break; case ::BRUTUS::ProxyManager::spawn_error_exception : return "Spawn failure: spawn_error_exception"; break; case ::BRUTUS::ProxyManager::spawn_error_impersonation : return "Spawn failure: spawn_error_impersonation"; break; case ::BRUTUS::ProxyManager::spawn_error_config : return "Spawn failure: spawn_error_config"; break; case ::BRUTUS::ProxyManager::spawn_error_corba : return "Spawn failure: spawn_error_corba"; break; case ::BRUTUS::ProxyManager::spawn_error_mapi_init : return "Spawn failure: spawn_error_mapi_init"; break; case ::BRUTUS::ProxyManager::spawn_error_spawn : return "Spawn failure: spawn_error_spawn"; break; case ::BRUTUS::ProxyManager::spawn_duplicate : return "Spawn failure: spawn_duplicate"; break; case ::BRUTUS::ProxyManager::spawn_ok : return "Spawn OK"; break; default : return "Unknown Spawn failure"; break; } } static inline bool authenticate_user(const char *WindowsUserName, const char *WindowsDomainName, const char *WindowsUserPassword) { BRUTUS_LOG_REF; HANDLE credentials = NULL; if (LogonUser((char*)WindowsUserName, (char*)WindowsDomainName, (char*)WindowsUserPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &credentials)) { CloseHandle(credentials); return true; } if (credentials) CloseHandle(credentials); DWORD err = GetLastError(); char msg[512] = {0}; LPVOID msg_buf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg_buf, 0, NULL ); ((char*)msg_buf)[strlen((char*)msg_buf) - 2] = '\0'; _snprintf_s(msg, sizeof(msg), sizeof(msg), "LogonUser(%s\\%s) failed - GetLastError() returned: 0x%X (%s)", WindowsDomainName, WindowsUserName, err, (const char*)msg_buf); LocalFree(msg_buf); BRUTUS_LOG_SUB_PRIVATE(msg); return false; } BRUTUS_BrutusLogOn_i::BRUTUS_BrutusLogOn_i(::PortableServer::POA_ptr Poa, ::SessionRegistry *Registry, const bool ProcessPerSession, const bool OnlyAdministrator, const bool Authenticate, const bool ProfilesOnDisk, const unsigned long CheckLifeDelay, ::CORBA::ORB_ptr ORB) : poa_(::PortableServer::POA::_duplicate(Poa)), served_sessions_(Registry), process_per_session_(ProcessPerSession), only_administrator_(OnlyAdministrator), authenticate_(Authenticate), profiles_on_disk_(ProfilesOnDisk), exchange_2007_(false), check_life_delay_(CheckLifeDelay) { Config *conf = new Config(); // load configuration if (conf->load(BRUTUS_CONF)) { delete conf; throw 0; } // MAPI options char *exchange_version_str = NULL; exchange_version_str = conf->get_value("EXCHANGE_SERVER_VERSION"); if ((exchange_version_str) && (!strcmp(exchange_version_str, "2007"))) exchange_2007_ = true; free(exchange_version_str); delete conf; internal_orb_ = ::CORBA::ORB::_duplicate(ORB); proxy_manager_ = ::BRUTUS::ProxyManager::_nil(); if (process_per_session_) { try { ::CORBA::Object_var object = internal_orb_->string_to_object(PROXY_MANAGER_IOR); proxy_manager_ = ::BRUTUS::ProxyManager::_narrow(object.in()); } catch (...) { } } } void BRUTUS_BrutusLogOn_i::GetVersion(::BRUTUS::BrutusLogOn::BrutusVersion_out version) { BRUTUS_LOG_REF; BRUTUS_LOG_SUB_INF("Entering BRUTUS_BrutusLogOn_i::GetVersion()"); ::BRUTUS::BrutusLogOn::BrutusVersion_var ver; try { ver = new ::BRUTUS::BrutusLogOn::BrutusVersion; } catch (std::bad_alloc &) { BRUTUS_LOG_SUB_ERR("No memory"); throw ::CORBA::NO_MEMORY(); } ver->major = (::CORBA::UShort)BRUTUS_VERSION_MAJOR; ver->minor = (::CORBA::UShort)BRUTUS_VERSION_MINOR; ver->micro = (::CORBA::UShort)BRUTUS_VERSION_MICRO; ver->release_tag = (::CORBA::UShort)BRUTUS_VERSION_RELEASE_TAG; version = ver._retn(); BRUTUS_LOG_SUB_INF("Leaving BRUTUS_BrutusLogOn_i::GetVersion()"); } void BRUTUS_BrutusLogOn_i::GetPublicKey(::BRUTUS::seq_octet_out PubKey) { BRUTUS_LOG_REF; BRUTUS_LOG_SUB_INF("Entering BRUTUS_BrutusLogOn_i::GetPublicKey()"); char *key = NULL; int len = 0; struct _stat pk_stat = { 0 }; ::BRUTUS::seq_octet_var pubkey; try { pubkey = new ::BRUTUS::seq_octet; } catch (std::bad_alloc &) { BRUTUS_LOG_SUB_ERR("No memory"); throw ::CORBA::NO_MEMORY(); } pubkey->length(0); // get size of public key if (_stat(PUBLIC_KEY, &pk_stat)) { BRUTUS_LOG_SUB_ERR("Could not stat public key file"); goto exit; } key = (char*)malloc(pk_stat.st_size); if (!key) { BRUTUS_LOG_SUB_ERR("No memory"); throw ::CORBA::NO_MEMORY(); } FILE *file = NULL; if (fopen_s(&file, PUBLIC_KEY, "r")) { BRUTUS_LOG_SUB_ERR("Could not open public key file"); goto exit; } len = fscanf_s(file, "%as", &key, pk_stat.st_size); if (file) // C6387 fclose(file); if (!len) BRUTUS_LOG_SUB_ERR("Could not read public key"); else { unsigned long n = 0; pubkey->length(len); do { pubkey[n] = (::CORBA::Octet)key[n]; n++; } while(--len); } exit: free(key); PubKey = pubkey._retn(); BRUTUS_LOG_SUB_INF("Leaving BRUTUS_BrutusLogOn_i::GetPublicKey()"); } ::BRUTUS::BRESULT BRUTUS_BrutusLogOn_i::Logon(::BRUTUS::BrutusCheck_ptr LifeLine, const char *MAPIProfileName, const char *MAPIProfilePassword, const char *WindowsUserName, const char *WindowsDomainName, const char *WindowsUserPassword, const char *MailboxName, const char *ServerName, ::BRUTUS::BDEFINE LogonFlags, ::BRUTUS::BDEFINE ProfileFlags, ::BRUTUS::SERVER_TYPE ServerType, ::CORBA::ULong_out InstanceID, ::BRUTUS::IMAPISession_out Session) { BRUTUS_LOG_REF; Session = ::BRUTUS::IMAPISession::_nil(); if (::CORBA::is_nil(LifeLine)) { BRUTUS_LOG_SUB_BUG("LifeLine parameter was NIL"); return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER; } try { ::CORBA::String_var life_line_ior = internal_orb_->object_to_string(LifeLine); if (NULL == life_line_ior.in()) { BRUTUS_LOG_SUB_BUG("IOR is NULL"); return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER; } BRUTUS_LOG_SUB_INF("Validating LifeLine object reference"); BRUTUS_LOG_SUB_INF(life_line_ior.in()); LifeLine->ping(); } catch (const ::CORBA::TIMEOUT &) { BRUTUS_LOG_SUB_BUG("Timeout trying to validate lifeline"); return ::BRUTUS::BRUTUS_LIFELINE_TIMEOUT; } catch (const ::CORBA::Exception &e) { BRUTUS_LOG_SUB_BUG(e._info().c_str()); return ::BRUTUS::BRUTUS_EXCEPTION_FROM_CLIENT; } catch (...) { BRUTUS_LOG_SUB_BUG("Unknown exception caught"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } return create_session(check_life_delay_, LifeLine, MAPIProfileName, MAPIProfilePassword, WindowsUserName, (const char*)(strlen(WindowsDomainName) ? WindowsDomainName : NULL), // take care of UPN authentication WindowsUserPassword, MailboxName, ServerName, LogonFlags, ProfileFlags, ServerType, InstanceID, Session); } ::BRUTUS::BRESULT BRUTUS_BrutusLogOn_i::create_session(const unsigned long CheckLifeDelay, ::BRUTUS::BrutusCheck_ptr LifeLine, const char *MAPIProfileName, const char *MAPIProfilePassword, const char *WindowsUserName, const char *WindowsDomainName, const char *WindowsUserPassword, const char *MailboxName, const char *ServerName, ::BRUTUS::BDEFINE LogonFlags, ::BRUTUS::BDEFINE ProfileFlags, ::BRUTUS::SERVER_TYPE ServerType, ::CORBA::ULong_out InstanceID, ::BRUTUS::IMAPISession_out Session) { BRUTUS_LOG_REF; BRUTUS_LOG_SUB_INF("Entering BRUTUS_BrutusLogOn_i::Logon()"); bool null_profile_passwd = false; bool retry = true; ::BRUTUS::IMAPISession_var session = ::BRUTUS::IMAPISession::_nil(); ::BRUTUS::BRESULT br = ::BRUTUS::BRUTUS_INTERNAL_ERROR; const char *user = only_administrator_ ? "Administrator" : WindowsUserName; InstanceID = 0; Session = ::BRUTUS::IMAPISession::_nil(); if (authenticate_) { if (!authenticate_user(user, WindowsDomainName, WindowsUserPassword)) return ::BRUTUS::BRUTUS_MAPI_E_LOGON_FAILED; else { char msg[512] = {0}; sprintf_s(msg, sizeof(msg), "%s\\%s authenticated sucessfully - proceeding with logon", WindowsDomainName, user); BRUTUS_LOG_SUB_PRIVATE(msg); } } if (!MAPIProfileName || !strlen(MAPIProfileName)) return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER; else if (strlen(MAPIProfileName) > 64) return ::BRUTUS::BRUTUS_MAPI_E_STRING_TOO_LONG; if (MAPIProfilePassword && (strlen(MAPIProfilePassword) > 64)) return ::BRUTUS::BRUTUS_MAPI_E_STRING_TOO_LONG; if (!strlen(MAPIProfilePassword)) null_profile_passwd = true; BRUTUS_LOG_SUB_PRIVATE(MAPIProfileName); if (process_per_session_) { ::CORBA::Object_var object = ::CORBA::Object::_nil(); const char *server_type = NULL; switch (ServerType) { case ::BRUTUS::SERVER_TYPE_EXCHANGE: server_type = "MSEMS"; break; case ::BRUTUS::SERVER_TYPE_DOMINO: server_type = "NOTES"; break; default: BRUTUS_LOG_SUB_BUG("Message service not supported"); return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER; } if (::CORBA::is_nil(proxy_manager_.in())) { try { object = internal_orb_->string_to_object(PROXY_MANAGER_IOR); proxy_manager_ = ::BRUTUS::ProxyManager::_narrow(object.in()); } catch (...) { } } if (::CORBA::is_nil(proxy_manager_.in())) { BRUTUS_LOG_SUB_CRITICAL("Could not get Proxy Manager reference"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } try { ::CORBA::String_var life_line_ior = internal_orb_->object_to_string(LifeLine); if (NULL == life_line_ior.in()) { BRUTUS_LOG_SUB_BUG("IOR is NULL"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } if (!proxy_manager_->setUser(life_line_ior.in(), user, WindowsDomainName, WindowsUserPassword, MAPIProfileName, MAPIProfilePassword, MailboxName, ServerName, server_type, LogonFlags, ProfileFlags)) { char msg[512] = {0}; sprintf_s(msg, sizeof(msg), "Could not spawn proxy process for %s/%s. Impersonation failed, check user privileges.", user, WindowsDomainName); ACE_DEBUG((LM_CRITICAL, ACE_TEXT(msg))); BRUTUS_LOG_SUB_CRITICAL(msg); return ::BRUTUS::BRUTUS_MAPI_E_LOGON_FAILED; } } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } ::CORBA::String_var session_ior = (const char*)""; ::BRUTUS::ProxyManager::SpawnStatus spawn_status; try { // this call takes the longest time in the logon process spawn_status = proxy_manager_->getSession(MAPIProfileName, session_ior.out()); } catch (const ::CORBA::Exception &e) { BRUTUS_LOG_SUB_CRITICAL(e._info().c_str()); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } if ((spawn_status == ::BRUTUS::ProxyManager::spawn_ok) || (spawn_status == ::BRUTUS::ProxyManager::spawn_duplicate)) { try { object = internal_orb_->string_to_object(session_ior.in()); session = ::BRUTUS::IMAPISession::_narrow(object.in()); } catch (...) { return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } if (::CORBA::is_nil(object.in())) return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } else { switch (spawn_status) { case ::BRUTUS::ProxyManager::spawn_error_authentication : case ::BRUTUS::ProxyManager::spawn_error_mapi_logon : br = ::BRUTUS::BRUTUS_MAPI_E_LOGON_FAILED; break; case ::BRUTUS::ProxyManager::spawn_error_mapi_no_profile : br = ::BRUTUS::BRUTUS_MAPI_E_NOT_FOUND; break; case ::BRUTUS::ProxyManager::spawn_error_lifeline : br = ::BRUTUS::BRUTUS_LIFELINE_ERROR; break; case ::BRUTUS::ProxyManager::spawn_error_exception : case ::BRUTUS::ProxyManager::spawn_error_impersonation : case ::BRUTUS::ProxyManager::spawn_error_config : case ::BRUTUS::ProxyManager::spawn_error_corba : case ::BRUTUS::ProxyManager::spawn_error_mapi_init : case ::BRUTUS::ProxyManager::spawn_error_spawn : default : br = ::BRUTUS::BRUTUS_INTERNAL_ERROR; } BRUTUS_LOG_SUB_CRITICAL(spawn_status_msg(spawn_status)); return br; } // the user is already authenticated if (spawn_status == ::BRUTUS::ProxyManager::spawn_duplicate) { BRUTUS_LOG_SUB_INF("Duplicate session created"); InstanceID = session->addLifeline(LifeLine); } else { BRUTUS_LOG_SUB_INF("New session created"); InstanceID = 0; } br = ::BRUTUS::BRUTUS_S_OK; Session = session._retn(); } else { LPMAPISESSION mapi_session = NULL; FLAGS flags = native_logon_flags(LogonFlags); HRESULT hr = E_FAIL; create_mapi_session: hr = MAPILogonEx(0, (char*)MAPIProfileName, (char*)(null_profile_passwd ? NULL : MAPIProfilePassword), flags, &mapi_session); if (retry) { if ((!profiles_on_disk_ && (MAPI_E_LOGON_FAILED == hr)) || (profiles_on_disk_ && (MAPI_E_NOT_FOUND == hr))) { br = CreateProfile(MAPIProfileName, MAPIProfilePassword, MailboxName, ServerName, ServerType, ProfileFlags, (exchange_2007_ ? true : false)); if (::BRUTUS::BRUTUS_S_OK != br) { BRUTUS_LOG_SUB_CRITICAL("Could not create MAPI Profile - Incorrect user credentials or insufficient privileges"); return br; } retry = false; goto create_mapi_session; } } if (!hresult_to_bresult(hr, br)) { if (mapi_session) { BRUTUS_LOG_SUB_ERR("MAPI session is non-NIL but MAPILogonEx failed."); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } if (S_OK != hr) { if (mapi_session) { BRUTUS_LOG_SUB_ERR("MAPI session is non-NIL but MAPILogonEx failed."); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } } { char msg[128] = {0}; const char *reason; if (MAPI_E_TIMEOUT == hr) reason = "MAPI_E_TIMEOUT"; else reason = "MAPI_E_LOGON_FAILED"; sprintf_s(msg, sizeof(msg), "MAPILogonEx(%s) failed - %s", MAPIProfileName, reason); BRUTUS_LOG_SUB_PRIVATE(msg); } return br; } // create the child poa for this mapi session ::PortableServer::POA_var session_poa = ::PortableServer::POA::_nil(); again: try { session_poa = create_poa(MAPIProfileName, ::PortableServer::POAManager::_nil(), poa_.in()); } catch (::PortableServer::POA::AdapterAlreadyExists &) { BRUTUS_LOG_ERR("POA exists - terminating former instance, replacing with new..."); served_sessions_->sign_out(MAPIProfileName, 1); goto again; } if (::CORBA::is_nil(session_poa)) { BRUTUS_LOG_SUB_ERR("Could not create session POA"); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } // activate the IMAPISession object's poa so that requests can be served ::PortableServer::POAManager_var poa_manager = session_poa->the_POAManager(); try { poa_manager->activate(); } catch (::PortableServer::POAManager::AdapterInactive &) { BRUTUS_LOG_SUB_CRITICAL("POAManager::activate() throwed an exception"); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } // the session poa is now created so add it to the session registry unsigned long id = served_sessions_->add_entry(session_poa.in(), MAPIProfileName); if (!id) { BRUTUS_LOG_SUB_ERR("Could not add entry into managed sessions"); session_poa->destroy(1, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } // create the IMAPISession servant BRUTUS_IMAPISession_i *mapi_session_servant; try { mapi_session_servant = new BRUTUS_IMAPISession_i(mapi_session, session_poa.in(), served_sessions_, id, internal_orb_.in(), LifeLine, CheckLifeDelay, false); } catch (std::bad_alloc &) { BRUTUS_LOG_SUB_ERR("No memory"); served_sessions_->sign_out(id, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_MAPI_E_NOT_ENOUGH_MEMORY; } // create the IMAPISession object and register it in the session poa ::PortableServer::ObjectId_var oid; try { ::PortableServer::ServantBase_var owner_transfer(mapi_session_servant); oid = session_poa->activate_object(mapi_session_servant); } catch (const ::PortableServer::POA::WrongPolicy &) { BRUTUS_LOG_SUB_CRITICAL("::PortableServer::POA::WrongPolicy exception caught"); served_sessions_->sign_out(id, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } catch (const ::PortableServer::POA::ServantAlreadyActive &) { BRUTUS_LOG_SUB_CRITICAL("::PortableServer::POA::ServantAlreadyActive exception caught"); served_sessions_->sign_out(id, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } // get the object reference ::CORBA::Object_var obj = ::CORBA::Object::_nil(); try { obj = session_poa->id_to_reference(oid.in()); } catch (const ::PortableServer::POA::WrongPolicy &) { BRUTUS_LOG_SUB_CRITICAL("::PortableServer::POA::WrongPolicy exception caught"); } catch (const ::PortableServer::POA::ObjectNotActive &) { BRUTUS_LOG_SUB_CRITICAL("::PortableServer::POA::ObjectNotActive exception caught"); } if (::CORBA::is_nil(obj)) { BRUTUS_LOG_SUB_CRITICAL("::PortableServer::POA::id_to_reference() returned NIL"); served_sessions_->sign_out(id, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } session = ::BRUTUS::IMAPISession::_narrow(obj); if (::CORBA::is_nil(session)) { BRUTUS_LOG_SUB_CRITICAL("::BRUTUS::IMAPISession::_narrow() returned NIL"); served_sessions_->sign_out(id, 0); try { mapi_session->Release(); } catch (...) { BRUTUS_LOG_SUB_CRITICAL("Exception caught"); } return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } Session = session._retn(); { char msg[128] = {0}; sprintf_s(msg, sizeof(msg), "%s has logged on", MAPIProfileName); BRUTUS_LOG_SUB_PRIVATE(msg); } br = ::BRUTUS::BRUTUS_S_OK; } BRUTUS_LOG_SUB_PRIVATE(MAPIProfileName); BRUTUS_LOG_SUB_INF("Leaving BRUTUS_BrutusLogOn_i::Logon()"); return br; } ::BRUTUS::BRESULT BRUTUS_BrutusLogOn_i::CreateProfile(const char *MAPIProfileName, const char *MAPIProfilePassword, const char *MailboxName, const char *ServerName, ::BRUTUS::SERVER_TYPE ServerType, ::BRUTUS::BDEFINE ProfileFlags, ::CORBA::Boolean ConnectIgnoreNoPF) { BRUTUS_LOG_REF; BRUTUS_LOG_SUB_INF("Entering BRUTUS_BrutusLogOn_i::CreateProfile()"); if (!MAPIProfileName) return ::BRUTUS::BRUTUS_MAPI_E_INVALID_PARAMETER; else if (strlen(MAPIProfileName) > 64) return ::BRUTUS::BRUTUS_MAPI_E_STRING_TOO_LONG; if (MAPIProfilePassword && (strlen(MAPIProfilePassword) > 64)) return ::BRUTUS::BRUTUS_MAPI_E_STRING_TOO_LONG; if (!strlen(MAPIProfilePassword)) MAPIProfilePassword = NULL; BRUTUS_LOG_SUB_PRIVATE(MAPIProfileName); BRUTUS_LOG_SUB_PRIVATE(MailboxName); BRUTUS_LOG_SUB_PRIVATE(ServerName); const char *server_type = NULL; const char *service_display_name = NULL; LPPROFSECT lpProfSect = NULL; LPPROFADMIN lpProfAdmin = NULL; LPSERVICEADMIN lpSvcAdmin = NULL; LPMAPITABLE lpMsgSvcTable = NULL; SRestriction sres; SPropValue SvcProps; LPSRowSet lpSvcRows = NULL; // Rowset to hold results of table query. SPropValue rgval[2]; // Property structure to hold values we want to set. ::BRUTUS::BRESULT br = ::BRUTUS::BRUTUS_INTERNAL_ERROR; HRESULT hr = S_OK; // I am not entirely clear on this. I don't feel good about initializing MAPI // several times in the same thread and this method is a one-time call anyway // so I better just serialize it with a RW mutex. ACE_Write_Guard guard(mutex_); if (process_per_session_) { MAPIINIT_0 mapi_init; mapi_init.ulFlags = MAPI_MULTITHREAD_NOTIFICATIONS | MAPI_NT_SERVICE | (profiles_on_disk_ ? MAPI_TEMPORARY_PROFILES : 0); mapi_init.ulVersion = MAPI_INIT_VERSION; hr = MAPIInitialize(&mapi_init); if (hr != S_OK) { BRUTUS_LOG_SUB_CRITICAL("Could not initialize MAPI"); return ::BRUTUS::BRUTUS_INTERNAL_ERROR; } BRUTUS_LOG_SUB_INF("MAPI is initialized"); } FLAGS flags = native_create_profile_flags(ProfileFlags); // This indicates columns we want returned from HrQueryAllRows. SizedSPropTagArray(2, sptCols) = { 2, PR_SERVICE_NAME, PR_SERVICE_UID }; // Get an IProfAdmin interface. hr = MAPIAdminProfiles(0, &lpProfAdmin); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("MAPIAdminProfiles() failed"); goto out; } // Create a new profile. hr = lpProfAdmin->CreateProfile((char*)MAPIProfileName, (char*)MAPIProfilePassword, NULL, flags); if (hr != S_OK) { char __msg[128] = { 0 }; sprintf_s(__msg, sizeof(__msg), "Could not create profile, HRESULT = %#.8lx (", hr); strcat_s(__msg, sizeof(__msg) - strlen(__msg), hresult_to_str(hr)); strcat_s(__msg, sizeof(__msg) - strlen(__msg), ")"); BRUTUS_LOG_SUB_BUG(__msg); goto out; } // Get an IMsgServiceAdmin interface off of the IProfAdmin interface. hr = lpProfAdmin->AdminServices((char*)MAPIProfileName, (char*)MAPIProfilePassword, NULL, flags, &lpSvcAdmin); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("Could not get IMsgServiceAdmin interface"); goto out; } // Create the new message service for a supported server type. switch (ServerType) { case ::BRUTUS::SERVER_TYPE_EXCHANGE: server_type = "MSEMS"; service_display_name = "Microsoft Exchange"; break; case ::BRUTUS::SERVER_TYPE_DOMINO: server_type = "NOTES"; service_display_name = "Lotus Notes Mail"; break; default: BRUTUS_LOG_SUB_BUG("Message service not supported"); hr = MAPI_E_INVALID_PARAMETER; goto out; } hr = lpSvcAdmin->CreateMsgService((LPTSTR)server_type, // Name of service from MAPISVC.INF. (LPTSTR)service_display_name, NULL, flags); if (hr != S_OK) { ACE_LOG_MSG->open("Brutus Server", ACE_Log_Msg::SYSLOG); switch (ServerType) { case ::BRUTUS::SERVER_TYPE_EXCHANGE: BRUTUS_LOG_SUB_ERR("The MSEMS message service is not in the [Services] section of MAPISVC.INF.\n\t Please see http://support.microsoft.com/?kbid=294470\n\t You can use the MAPIsvc application that is distributed with Brutus instead of mergeini."); ACE_DEBUG((LM_CRITICAL, ACE_TEXT("The MSEMS message service is not in the [Services] section of \"MAPISVC.INF\". Please see http://support.microsoft.com/?kbid=294470. You can use the MAPIsvc application that is distributed with Brutus instead of mergeini."))); break; case ::BRUTUS::SERVER_TYPE_DOMINO: BRUTUS_LOG_SUB_ERR("The NOTES message service is not in the [Services] section of MAPISVC.INF.\n\t Please see http://support.microsoft.com/?kbid=294470\n\t You can use the MAPIsvc application that is distributed with Brutus instead of mergeini."); ACE_DEBUG((LM_CRITICAL, ACE_TEXT("The NOTES message service is not in the [Services] section of \"MAPISVC.INF\". Please see http://support.microsoft.com/?kbid=294470. You can use the MAPIsvc application that is distributed with Brutus instead of mergeini."))); break; default: BRUTUS_LOG_SUB_ERR("Unknown and unsupported message service."); ACE_DEBUG((LM_CRITICAL, ACE_TEXT("Unknown and unsupported message service"))); break; } goto out; } // We now need to get the entry id for the new service. // This can be done by getting the message service table // and getting the entry that corresponds to the new service. hr = lpSvcAdmin->GetMsgServiceTable(flags, &lpMsgSvcTable); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("Could not get message service table"); goto out; } // Set up restriction to query table. sres.rt = RES_CONTENT; sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING; sres.res.resContent.ulPropTag = PR_SERVICE_NAME; sres.res.resContent.lpProp = &SvcProps; SvcProps.ulPropTag = PR_SERVICE_NAME; SvcProps.Value.lpszA = (LPTSTR)server_type; // Query the table to get the entry for the newly created message service. hr = HrQueryAllRows(lpMsgSvcTable, (LPSPropTagArray)&sptCols, &sres, NULL, 0, &lpSvcRows); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("HrQueryAllRows() failed"); goto out; } if (1 != lpSvcRows->cRows) { BRUTUS_LOG_SUB_BUG("Wrong number of rows"); goto out; } // Setup a SPropValue array for the properties you need to configure. // the mailbox name. memset((void*)&rgval[0], 0, sizeof(SPropValue)); rgval[0].ulPropTag = PR_PROFILE_UNRESOLVED_NAME; rgval[0].Value.lpszA = (char*)MailboxName; // the server name. memset((void*)&rgval[1], 0, sizeof(SPropValue)); rgval[1].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER; rgval[1].Value.lpszA = (char*)ServerName; // Configure the message service with the above properties. hr = lpSvcAdmin->ConfigureMsgService((LPMAPIUID)lpSvcRows->aRow[0].lpProps[1].Value.bin.lpb, // Entry ID of service to configure. NULL, flags, 2, // Number of properties we are setting. rgval); if (hr != S_OK) { BRUTUS_LOG_HR; BRUTUS_LOG_SUB_BUG("Could not configure message service"); } if (ConnectIgnoreNoPF) { LPSPropValue flags_pv = NULL; hr = lpSvcAdmin->OpenProfileSection((LPMAPIUID)pbGlobalProfileSectionGuid, NULL, MAPI_MODIFY, &lpProfSect); if (hr != S_OK) { hr = lpSvcAdmin->OpenProfileSection((LPMAPIUID)pbGlobalProfileSectionGuid, NULL, MAPI_MODIFY | MAPI_FORCE_ACCESS, &lpProfSect); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("OpenProfileSection() failed"); goto out; } } hr = HrGetOneProp(lpProfSect, PR_PROFILE_CONNECT_FLAGS, &flags_pv); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("HrGetOneProp() failed"); goto out; } flags_pv->Value.l |= CONNECT_IGNORE_NO_PF; hr = HrSetOneProp(lpProfSect, flags_pv); MAPIFreeBuffer(flags_pv); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("HrSetOneProp() failed"); goto out; } hr = lpProfSect->SaveChanges(FORCE_SAVE); if (hr != S_OK) { BRUTUS_LOG_SUB_BUG("HrSetOneProp() failed"); goto out; } BRUTUS_LOG_SUB_INF("CONNECT_IGNORE_NO_PF flag set"); } out: if ((S_OK != hr) && (MAPI_E_NO_ACCESS != hr)) lpProfAdmin->DeleteProfile((char*)MAPIProfileName, 0); if (!hresult_to_bresult(hr, br)) { BRUTUS_LOG_SUB_BUG("Could not convert HRESULT into BRESULT"); BRUTUS_SUB_EXIT; exit: br = ::BRUTUS::BRUTUS_INTERNAL_ERROR; } if (lpSvcRows) FreeProws(lpSvcRows); if (lpMsgSvcTable) lpMsgSvcTable->Release(); if (lpSvcAdmin) lpSvcAdmin->Release(); if (lpProfAdmin) lpProfAdmin->Release(); if (lpProfSect) lpProfSect->Release(); if (process_per_session_) MAPIUninitialize(); return br; }