/*--------------------------------------------------------------------------- File: AgentRpc.cpp Comments: RPC interface for DCT Agent service (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved Proprietary and confidential to Mission Critical Software, Inc. REVISION LOG ENTRY Revision By: Christy Boles Revised on 02/19/99 11:39:58 --------------------------------------------------------------------------- */ #include #include #include "AgSvc.h" #include "Common.hpp" #include "UString.hpp" #include "Err.hpp" #include "TEvent.hpp" #include "EaLen.hpp" #include "Cipher.hpp" #include "IsAdmin.hpp" #include "ResStr.h" #include "TSync.hpp" //#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids //#import "\bin\MCSEADCTAgent.tlb" no_namespace, named_guids #import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty") #import "Engine.tlb" no_namespace, named_guids #include "TNode.hpp" #ifdef OFA #include "atlbase.h" #endif extern LPSTREAM pStream; extern TCriticalSection gStreamCS; extern TErrorEventLog err; extern BOOL gSuicide; extern BOOL gDebug; extern BOOL gLocallyInstalled; extern BOOL gbFinished; extern BOOL gbIsNt351; extern StringLoader gString; DWORD RemoveService(); DWORD UnregisterFiles(); DWORD RemoveFiles(); DWORD RegisterDLL(const WCHAR * filename); DWORD RegisterExe(const WCHAR * filename); BOOL IsLocallyInstalled(); DWORD __stdcall ShutdownService( /* [in] */ DWORD bFlags ); TNodeList gJobList; class TJobNode : public TNode { WCHAR guid[LEN_Guid]; public: TJobNode(WCHAR const * id) { safecopy(guid,id); } WCHAR const * JobID() { return guid; } }; // thread entry point, waits for the specified job to end, // then shuts down the DCTAgentService DWORD __stdcall MonitorJob( void * arg // in - BSTR job ID ) { HRESULT hr = CoInitialize(NULL); _bstr_t jobID = (BSTR)arg; IDCTAgent * pLocalAgent = NULL; BOOL bDone = FALSE; try { // Get a pointer to the local agent if ( SUCCEEDED(hr) ) { gStreamCS.Enter(); // this critical section is used to ensure that // only one process is unmarshalling pStream at a time hr = CoUnmarshalInterface( pStream, IID_IDCTAgent,(void**)&pLocalAgent); HRESULT hr2; if ( SUCCEEDED(hr) ) { // Reset the stream to the beginning LARGE_INTEGER offset = { 0,0 }; ULARGE_INTEGER result = { 0,0 }; hr2 = pStream->Seek(offset,STREAM_SEEK_SET,&result); } gStreamCS.Leave(); if (FAILED(hr2)) err.SysMsgWrite(ErrE, hr2, DCT_MSG_SEEK_FAILED_D, hr2); // Get the status of the job IUnknown * pUnk = NULL; if ( SUCCEEDED(hr) ) { do { hr = pLocalAgent->raw_QueryJobStatus(jobID,&pUnk); if ( SUCCEEDED(hr) ) { IVarSetPtr pVarSet = pUnk; _bstr_t status = pVarSet->get(GET_BSTR(DCTVS_JobStatus)); _bstr_t shutdownStatus = pVarSet->get(GET_BSTR(DCTVS_ShutdownStatus)); if ( gDebug ) { err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_MONJOBSTAT),(WCHAR*)jobID, (WCHAR*)status); } // only when the agent finishes and is ready to shut down, do we shut down if (( ! UStrICmp(status,GET_STRING(IDS_DCT_Status_Completed)) || ! UStrICmp(status,GET_STRING(IDS_DCT_Status_Completed_With_Errors))) && ! UStrICmp(shutdownStatus,GET_STRING(IDS_DCT_Status_Shutdown))) { bDone = TRUE; break; } } else { // if we are unable to query the agent, it indicates something serious happened // we should shut down the service bDone = TRUE; if (gDebug) err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_CANNOT_MONITOR_JOB),(WCHAR*)jobID, hr); } pUnk->Release(); pUnk = NULL; Sleep(60*1000); // one minute } while ( SUCCEEDED(hr) ); pLocalAgent->Release(); } else { // cannot unmarshal the agent, shut down the service bDone = TRUE; } CoUninitialize(); } else { bDone = TRUE; } } catch ( ... ) { bDone = TRUE; if (gDebug) err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_MONERROR)); try { pLocalAgent->Release(); } catch ( ... ) { } } if (bDone) hr = ShutdownService(0); if ( gDebug ) err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_MONEXIT),hr); return hr; } DWORD AuthenticateClient( handle_t hBinding // in - binding for client call ) { DWORD rc; rc = RpcImpersonateClient(hBinding); if ( rc ) { err.SysMsgWrite(ErrE,rc,DCT_MSG_FAILED_TO_IMPERSONATE_D,rc); } else { rc = IsAdminLocal(); if ( rc ) { err.SysMsgWrite(ErrE,rc,DCT_MSG_CLIENT_NOT_ADMIN_D, rc); } RpcRevertToSelf(); } return rc; } DWORD RegisterPlugInFiles( IVarSet * pVarSet ) { DWORD rc = 0; WCHAR key[MAX_PATH + 50]; int nFiles = 0; _bstr_t filename; do { if ( gDebug ) //* err.DbgMsgWrite(0,L"Starting plug-in file registration."); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_STARTPLUGREG)); swprintf(key,GET_STRING(IDS_DCTVSFmt_PlugIn_RegisterFiles_D),nFiles); filename = pVarSet->get(key); if ( filename.length() != 0 ) { if ( gDebug ) //* err.DbgMsgWrite(0,L"File %ld = %ls",nFiles,(WCHAR*)filename); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_FILEREG),nFiles,(WCHAR*)filename); if ( !UStrICmp((WCHAR *)filename + filename.length() - 4,L".DLL") ) { RegisterDLL(filename); } else { RegisterExe(filename); } nFiles++; } } while (filename.length() != 0); if ( gDebug ) //* err.DbgMsgWrite(0,L"Done Registering plug-in files."); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_PLUGREGDONE)); return rc; } DWORD __stdcall EaxsSubmitJob( /* [in] */ handle_t hBinding, /* [string][in] */ const WCHAR __RPC_FAR *filename, /* [string][in] */ const WCHAR __RPC_FAR *extra, /* [size_is][string][out] */ WCHAR __RPC_FAR *jobGUID ) { HRESULT hr = 0; WCHAR filenameW[MAX_PATH]; WCHAR pathW[MAX_PATH]; int pathLen = 0; IDCTAgent * pLocalAgent = NULL; // BOOL bFileCopied = FALSE; BOOL gbDeleteOnCompletion = FALSE; // Make sure the client is an admin on the local machine, otherwise, forget it hr = AuthenticateClient(hBinding); if ( hr ) { return hr; } safecopy(filenameW,filename); // get the path for our install directory if ( ! GetModuleFileName(NULL,pathW,DIM(pathW)) ) { hr = GetLastError(); pathW[0] = L'\0'; // to keep PREfast happy safecopy(pathW,filenameW); err.SysMsgWrite(ErrW,hr,DCT_MSG_GET_MODULE_PATH_FAILED_D,hr); } else { pathW[DIM(pathW) - 1] = L'\0'; pathLen = UStrLen(pathW) - UStrLen(GET_STRING(IDS_SERVICE_EXE)); UStrCpy(pathW + pathLen,filenameW, DIM(pathW)); } gStreamCS.Enter(); // this critical section is used to ensure that only one // process is unmarshalling pStream at a time hr = CoUnmarshalInterface( pStream, IID_IDCTAgent,(void**)&pLocalAgent); // interface pointer requested in riid); if ( SUCCEEDED(hr) ) { // Reset the stream to the beginning LARGE_INTEGER offset = { 0,0 }; ULARGE_INTEGER result = { 0,0 }; HRESULT hr2 = pStream->Seek(offset,STREAM_SEEK_SET,&result); gStreamCS.Leave(); if (FAILED(hr2)) err.SysMsgWrite(ErrE, hr2, DCT_MSG_SEEK_FAILED_D, hr2); BSTR jobID = NULL; // Read the varset data from the file IVarSetPtr pVarSet; IStoragePtr store = NULL; // Try to create the COM objects hr = pVarSet.CreateInstance(CLSID_VarSet); if ( SUCCEEDED(hr) ) { // Read the VarSet from the data file hr = StgOpenStorage(pathW,NULL,STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&store); if ( SUCCEEDED(hr) ) { // Load the data into a new varset hr = OleLoad(store,IID_IUnknown,NULL,(void **)&pVarSet); if ( SUCCEEDED(hr) ) { _bstr_t text = pVarSet->get(GET_BSTR(DCTVS_Options_DeleteFileAfterLoad)); if ( !UStrICmp(text,GET_STRING(IDS_YES)) ) { // Free the storage pointer to the file store = NULL; if ( DeleteFile(pathW) ) { if ( gDebug ) //* err.DbgMsgWrite(0,L"Deleted job file %ls",pathW); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_JOBDEL),pathW); } else { err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_JOB_FILE_NOT_DELETED_SD,pathW,GetLastError()); } } text = pVarSet->get(GET_BSTR(DCTVS_Options_RemoveAgentOnCompletion)); if ( !UStrICmp(text,GET_STRING(IDS_YES))) { gbDeleteOnCompletion = TRUE; } text = pVarSet->get(GET_BSTR(DCTVS_AgentService_DebugMode)); if ( !UStrICmp(text,GET_STRING(IDS_YES))) { gDebug = TRUE; } WCHAR password[LEN_Password]; safecopy(password,extra); RegisterPlugInFiles(pVarSet); // reset the absolute result file name based on the module file path _bstr_t relativeResultFileName = pVarSet->get(GET_BSTR(DCTVS_Options_RelativeResultFileName)); UStrCpy(pathW + pathLen, (!relativeResultFileName) ? L"" : (WCHAR*)relativeResultFileName, DIM(pathW)); pVarSet->put(GET_BSTR(DCTVS_Options_ResultFile), _bstr_t(pathW)); // reset the absolute .secrefs file name based on the module file path text = pVarSet->get(GET_BSTR(DCTVS_Security_ReportAccountReferences)); if (text.length()) { relativeResultFileName = pVarSet->get(GET_BSTR(DCTVS_Security_ReportAccountReferencesRelativeFileName)); UStrCpy(pathW + pathLen, (!relativeResultFileName) ? L"" : (WCHAR*)relativeResultFileName, DIM(pathW)); pVarSet->put(GET_BSTR(DCTVS_Security_ReportAccountReferences), _bstr_t(pathW)); } hr = pLocalAgent->raw_SubmitJob(pVarSet,&jobID); if ( SUCCEEDED(hr)) { TJobNode * pnode = new TJobNode(jobID); gJobList.InsertBottom(pnode); err.MsgWrite(0,DCT_MSG_AGENT_JOB_STARTED_SSS,jobID,L"",L""); } else { err.SysMsgWrite(ErrE,hr,DCT_MSG_SUBMIT_JOB_FAILED_D,hr); } if ( gbDeleteOnCompletion ) { if ( ! gLocallyInstalled ) { gSuicide = TRUE; } if ( SUCCEEDED(hr) ) { // Start up a thread to monitor this job and initiate a shutdown when it is completed DWORD threadID = 0; HANDLE gThread = CreateThread(NULL,0,&MonitorJob,(void*)jobID,0,&threadID); CloseHandle(gThread); } } UStrCpy(jobGUID,jobID); } else { err.SysMsgWrite(ErrE,HRESULT_CODE(hr),DCT_MSG_VARSET_LOAD_FAILED_SD,filenameW, hr); } } else { err.SysMsgWrite(ErrE,HRESULT_CODE(hr),DCT_MSG_JOBFILE_OPEN_FAILED_SD,filenameW,hr); } } // int x = pLocalAgent->Release(); pLocalAgent->Release(); } else { gStreamCS.Leave(); err.SysMsgWrite(ErrE,hr,DCT_MSG_UMARSHAL_AGENT_FAILED_D,hr); } return hr; } DWORD __stdcall EaxsQueryInterface( /* [in] */ handle_t hBinding, /* [out] */ LPUNKNOWN __RPC_FAR *lpAgentUnknown ) { DWORD rc = 0; HRESULT hr; IDCTAgent * pLocalAgent = NULL; (*lpAgentUnknown) = NULL; // make sure the client is an admin on the local machine rc = AuthenticateClient(hBinding); if ( rc ) { return rc; } if ( ! gbIsNt351 ) { gStreamCS.Enter(); // this critical section is used to ensure that // only one process is unmarshalling pStream at a time hr = CoUnmarshalInterface( pStream, IID_IUnknown,(void**)&pLocalAgent); // interface pointer requested in riid); if ( SUCCEEDED(hr) ) { // Reset the stream to the beginning LARGE_INTEGER offset = { 0,0 }; ULARGE_INTEGER result = { 0,0 }; HRESULT hr2 = pStream->Seek(offset,STREAM_SEEK_SET,&result); gStreamCS.Leave(); if (FAILED(hr2)) err.SysMsgWrite(ErrE, hr2, DCT_MSG_SEEK_FAILED_D, hr2); (*lpAgentUnknown) = pLocalAgent; } else { gStreamCS.Leave(); err.SysMsgWrite(ErrE,hr,DCT_MSG_UMARSHAL_AGENT_FAILED_D,hr); (*lpAgentUnknown) = NULL; } } else { // NT 3.51 doesn't support DCOM, so there's no point in even trying this (*lpAgentUnknown) = NULL; hr = E_NOTIMPL; } return hr; } #define DCTAgent_Remove 1 DWORD __stdcall ShutdownService( /* [in] */ DWORD bFlags ) { DWORD rc = 0; HRESULT hr; // LPUNKNOWN pLocalAgent = NULL; if ( bFlags ) { if ( gDebug ) //* err.DbgMsgWrite(0,L"Set suicide flag."); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_SETFLAG)); gSuicide = TRUE; } else { if ( gDebug ) //* err.DbgMsgWrite(0,L"Did not set suicide flag"); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_NOSETFLAG)); } if ( gSuicide && ! gLocallyInstalled ) { if ( gDebug ) //* err.DbgMsgWrite(ErrW,L"Removing agent"); err.DbgMsgWrite(ErrW,GET_STRING(IDS_EVENTVW_MSG_REMOVEAGENT)); // Uninstall the service if ( gDebug ) //* err.DbgMsgWrite(0,L"Unregistering files"); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_UNREGFILES)); UnregisterFiles(); // delete all files if ( gDebug ) //* err.DbgMsgWrite(0,L"Deleting files"); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_FILEDEL)); RemoveFiles(); if ( gDebug ) //* err.DbgMsgWrite(0,L"Removing service"); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_REMOVESVC)); RemoveService(); } else { if ( gDebug ) //* err.DbgMsgWrite(ErrW,L"Not Removing agent"); err.DbgMsgWrite(ErrW,GET_STRING(IDS_EVENTVW_MSG_NOREMOVEAGENT)); } RPC_STATUS status = RPC_S_OK; if ( ! gbIsNt351 ) { status = RpcMgmtStopServerListening(NULL); } else { gbFinished = TRUE; } if (gDebug) { if (status == RPC_S_OK) err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_STOPLISTEN),bFlags); else err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_CANNOT_STOP_LISTENING),(long)status); } status = RpcServerUnregisterIf( NULL, NULL, FALSE ); if (gDebug) { if (status == RPC_S_OK) err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_UNREGISTER_INTERFACE)); else err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_CANNOT_UNREGISTER_INTERFACE),(long)status); } return rc; }