/*--------------------------------------------------------------------------- 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" //#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 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) ) { hr = CoUnmarshalInterface( pStream, IID_IDCTAgent,(void**)&pLocalAgent); if ( SUCCEEDED(hr) ) { // Reset the stream to the beginning LARGE_INTEGER offset = { 0,0 }; ULARGE_INTEGER result = { 0,0 }; hr = pStream->Seek(offset,STREAM_SEEK_SET,&result); } // 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)); if ( gDebug ) { //* err.DbgMsgWrite(0,L"Monitoring job %ls, Status: %ls",(WCHAR*)jobID, (WCHAR*)status); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_MONJOBSTAT),(WCHAR*)jobID, (WCHAR*)status); } if ( ! UStrICmp(status,GET_STRING(IDS_DCT_Status_Completed)) ) { bDone = TRUE; break; } } pUnk->Release(); pUnk = NULL; Sleep(60*1000); // one minute } while ( SUCCEEDED(hr) ); // int x = pLocalAgent->Release(); pLocalAgent->Release(); } // TODO: make this an option if ( bDone ) { hr = ShutdownService(0); } CoUninitialize(); } } catch ( ... ) { //* err.DbgMsgWrite(0,L"An exception occurred while monitoring the job. Shutting down the agent service."); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_MONERROR)); try { pLocalAgent->Release(); } catch ( ... ) { } } if ( gDebug ) //* err.DbgMsgWrite(0,L"MonitorJob exiting, hr = %lx",hr); 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]; 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; } hr = CoInitialize(NULL); if ( FAILED(hr) ) { err.SysMsgWrite(ErrE,hr,DCT_MSG_COINITIALIZE_FAILED_D,hr); return hr; } safecopy(filenameW,filename); // get the path for our install directory if ( ! GetModuleFileName(NULL,pathW,DIM(pathW)) ) { hr = GetLastError(); safecopy(pathW,filenameW); err.SysMsgWrite(ErrW,hr,DCT_MSG_GET_MODULE_PATH_FAILED_D,hr); } else { UStrCpy(pathW + UStrLen(pathW) - UStrLen(GET_STRING(IDS_SERVICE_EXE)),filenameW, DIM(pathW)); } 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 }; hr = pStream->Seek(offset,STREAM_SEEK_SET,&result); 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); #ifdef OFA if(!IsLocallyInstalled()) #endif RegisterPlugInFiles(pVarSet); pVarSet->put(GET_BSTR(DCTVS_Options_Credentials_Password),password); 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 { err.SysMsgWrite(ErrE,hr,DCT_MSG_UMARSHAL_AGENT_FAILED_D,hr); } CoUninitialize(); return hr; } DWORD __stdcall EaxsCancelJob( /* [in] */ handle_t hBinding, /* [string][in] */ const WCHAR __RPC_FAR *jobGUID ) { DWORD rc = 0; HRESULT hr; IDCTAgent * pLocalAgent = NULL; // make sure the client is an admin on the local machine rc = AuthenticateClient(hBinding); if ( rc ) { return rc; } hr = CoInitialize(NULL); if ( FAILED(hr) ) { err.SysMsgWrite(ErrE,hr,DCT_MSG_COINITIALIZE_FAILED_D,hr); return hr; } 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}; hr = pStream->Seek(offset,STREAM_SEEK_SET,&result); BSTR jobID; jobID = SysAllocString(jobGUID); hr = pLocalAgent->CancelJob(jobID); if ( SUCCEEDED(hr)) { err.MsgWrite(0,DCT_MSG_JOB_CANCELLED_S,jobID); } pLocalAgent->Release(); rc = hr; } else { err.SysMsgWrite(ErrE,hr,DCT_MSG_UMARSHAL_AGENT_FAILED_D,hr); } CoUninitialize(); return rc; } 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; } hr = CoInitialize(NULL); if ( FAILED(hr) ) { err.SysMsgWrite(ErrE,hr,DCT_MSG_COINITIALIZE_FAILED_D,hr); return hr; } //E_NOINTERFACE if ( ! gbIsNt351 ) { 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 }; hr = pStream->Seek(offset,STREAM_SEEK_SET,&result); (*lpAgentUnknown) = pLocalAgent; } else { 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; hr = CoInitialize(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)); } if ( ! gbIsNt351 ) { RpcMgmtStopServerListening( NULL ); } else { gbFinished = TRUE; } RpcServerUnregisterIf( NULL, NULL, FALSE ); if ( gDebug ) //* err.DbgMsgWrite(0,L"Stopped listening(%ld)",bFlags); err.DbgMsgWrite(0,GET_STRING(IDS_EVENTVW_MSG_STOPLISTEN),bFlags); return rc; } DWORD __stdcall EaxsShutdown( /* [in] */ handle_t hBinding, /* [in] */ DWORD bFlags ) { DWORD rc = 0; // make sure the client is an admin on the local machine rc = AuthenticateClient(hBinding); if ( rc ) { return rc; } rc = ShutdownService(bFlags); return rc; }