//____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1996. // // File: job.cxx // // Contents: // // Classes: None. // // Functions: // // History: 14-Mar-96 EricB created // 21-Jun-96 MarkBl Renamed from jobedit.cxx since now Save() & // Get/SetAccountInformation members require // client-side rpc. Their implementations must // reside here so we don't have to include the // client-side RPC in the service. Also added // Get/SetAccountInformation members. // // Notes: Disabled security code completely for Win95. This will be // enabled in the next release of the scheduling agent. // // BUGBUG : The classes should be split into a core base class, // then have an OLE-supporting class inherit from it. // The core class would exist in the service. The sub- // class in the dll. // //____________________________________________________________________________ #include "..\pch\headers.hxx" #pragma hdrstop #if !defined(_CHICAGO_) #include "network.hxx" #endif // !defined(_CHICAGO_) #include "misc.hxx" #include "job_cls.hxx" #include "debug.hxx" #if !defined(_CHICAGO_) #include "defines.hxx" #endif // !defined(_CHICAGO_) #if !defined(_CHICAGO_) #include "SASecRPC.h" // Get/SetAccountInformation RPC definition. #endif // !defined(_CHICAGO_) #if !defined(_CHICAGO_) typedef DWORD (WINAPI * PWNETGETUNIVERSALNAMEW)(LPCWSTR, DWORD, LPVOID, LPDWORD); PWNETGETUNIVERSALNAMEW gpWNetGetUniversalNameW = NULL; #endif // !defined(_CHICAGO_) HRESULT DisplayJobProperties(LPTSTR, ITask *); // // This operation is not supported locally on Win95, and for the first // release of the scheduling agent, neither remotely from Win95 to NT. // #if !defined(_CHICAGO_) void ResetAccountInfo(PJOB_ACCOUNT_INFO pAccountInfo); #endif // !defined(_CHICAGO_) //+---------------------------------------------------------------------------- // // Member: CJob::ITask::EditWorkItem // // Synopsis: Invoke the edit job property sheet. // //----------------------------------------------------------------------------- STDMETHODIMP CJob::EditWorkItem(HWND hParent, DWORD dwReserved) { if (m_ptszFileName != NULL && m_ptszFileName[0] != TEXT('\0')) { return DisplayJobProperties(m_ptszFileName, (ITask *)this); } return STG_E_NOTFILEBASEDSTORAGE; } //+---------------------------------------------------------------------------- // // CJob::IProvideTaskPage::GetPage method // //----------------------------------------------------------------------------- STDMETHODIMP I_GetTaskPage( ITask * pITask, TASKPAGE tpType, BOOL fPersistChanges, HPROPSHEETPAGE * phPage); STDMETHODIMP CJob::GetPage( TASKPAGE tpType, BOOL fPersistChanges, HPROPSHEETPAGE * phPage) { return I_GetTaskPage((ITask *)this, tpType, fPersistChanges, phPage); } //+---------------------------------------------------------------------------- // // Member: CJob::ITask::SetAccountInformation // // Synopsis: Set the name and password of the account to be used for running // this job. // // Arguments: [pwszAccountName] -- Account name. // [pwszPassword] -- Account password. // // Returns: S_OK // E_INVALIDARG // E_OUTOFMEMORY // // Notes: Both strings are caller allocated and freed. // //----------------------------------------------------------------------------- STDMETHODIMP CJob::SetAccountInformation(LPCWSTR pwszAccountName, LPCWSTR pwszPassword) { TRACE(CJob, SetAccountInformation) if( NULL == pwszAccountName ) { return E_INVALIDARG; } // // This operation is not supported locally on Win95, and for the first // release of the scheduling agent, neither remotely from Win95 to NT. // #if !defined(_CHICAGO_) HRESULT hr; // // Need to allocate the private data member structure containing copies // of the account arguments. // // Note, could allocate everything within a single buffer, but since // this operation is performed so rarely, it really isn't worth it. // PJOB_ACCOUNT_INFO pAccountInfo = new JOB_ACCOUNT_INFO; if (pAccountInfo == NULL) { return(E_OUTOFMEMORY); } pAccountInfo->pwszPassword = NULL; pAccountInfo->pwszAccount = new WCHAR[wcslen(pwszAccountName) + 1]; if (pAccountInfo->pwszAccount != NULL) { wcscpy(pAccountInfo->pwszAccount, pwszAccountName); } else { hr = E_OUTOFMEMORY; goto ErrorExit; } if (pwszPassword != NULL) { pAccountInfo->pwszPassword = new WCHAR[wcslen(pwszPassword) + 1]; if (pAccountInfo->pwszPassword != NULL) { wcscpy(pAccountInfo->pwszPassword, pwszPassword); } else { hr = E_OUTOFMEMORY; goto ErrorExit; } } if (m_pAccountInfo != NULL) { ResetAccountInfo(m_pAccountInfo); delete m_pAccountInfo; } m_pAccountInfo = pAccountInfo; // // Setting this flag will result in the RPC call to set the account // information on object save (IPersistFile::Save()). // this->SetFlag(JOB_I_FLAG_SET_ACCOUNT_INFO); return(S_OK); ErrorExit: if (pAccountInfo != NULL) { ResetAccountInfo(pAccountInfo); delete pAccountInfo; } return(hr); #else return(SCHED_E_NO_SECURITY_SERVICES); #endif // !defined(_CHICAGO) } //+---------------------------------------------------------------------------- // // Member: CJob::ITask::GetAccountInformation // // Synopsis: Get the name of the account to be used for this job. // // Arguments: [ppwszAccountName] - the returned string buffer // // Returns: HRESULTS // // Notes: The string is callee allocated and caller freed with // CoTaskMemFree. // //----------------------------------------------------------------------------- STDMETHODIMP CJob::GetAccountInformation(LPWSTR * ppwszAccountName) { TRACE3(CJob, GetAccountInformation) // // This operation is not supported locally on Win95, and for the first // release of the scheduling agent, neither remotely from Win95 to NT. // #if !defined(_CHICAGO_) HRESULT hr; // // Unexpected, but possible should the caller CoCreateInstance a new // job, then call this member w/o IPersistFile::Load/Save. // if (m_ptszFileName == NULL) { schDebugOut((DEB_ERROR, "GetAccountInformation called with no filename\n")); return(E_UNEXPECTED); } // // Return cached account name. If it hasn't been obtained, we'll // need to RPC to the server to get it. // WCHAR wszAccountName[MAX_USERNAME + 1]; WCHAR * pwszAccountName = NULL; if (m_pAccountInfo == NULL) { // // RPC to the server local to this job to fetch the account name // associated with this job. // // First, figure out if this is a remote job. If so, fetch the server // name on which the job resides. // WCHAR wszFileName[MAX_PATH + 1] = L""; WCHAR wszUNCPath[MAX_PATH + 1]; WCHAR * pwszFileName; WCHAR * pwszServerName; #if !defined(UNICODE) HRESULT hr = AnsiToUnicode(wszFileName, m_ptszFileName, MAX_PATH+1); if (FAILED(hr)) { return E_INVALIDARG; } pwszFileName = wszFileName; #else pwszFileName = m_ptszFileName; #endif // UNICODE // // Fetch the server name associated with the network path. If the path // is local, the server name returned will be NULL. // hr = GetServerNameFromPath(pwszFileName, (MAX_PATH + 1) * sizeof(WCHAR), wszUNCPath, &pwszServerName); if (FAILED(hr)) { return(hr); } #if defined(_CHICAGO_) // // Local security operations are not supported on Win95. // if (pwszServerName == NULL) { return(SCHED_E_NO_SECURITY_SERVICES); } #endif // _CHICAGO_ // // RPC to the service to fetch the account name. // // First, isolate the relative job name from the remaining path. // WCHAR * pwszRelativeFileName; if (pwszFileName != NULL) { pwszRelativeFileName = wcsrchr(pwszFileName, L'\\'); if (pwszRelativeFileName != NULL) { pwszRelativeFileName++; } else { pwszRelativeFileName = pwszFileName; } } DWORD ccAccountName = MAX_USERNAME; RpcTryExcept { hr = SAGetAccountInformation(pwszServerName, pwszRelativeFileName, ccAccountName, wszAccountName); } RpcExcept(1) { DWORD Status = RpcExceptionCode(); schDebugOut((DEB_ERROR, "GetAccountInformation exception(0x%x)\n", Status)); hr = SchedMapRpcError(Status); } RpcEndExcept; if (SUCCEEDED(hr)) { pwszAccountName = wszAccountName; } } else { schAssert(m_pAccountInfo->pwszAccount != NULL); pwszAccountName = m_pAccountInfo->pwszAccount; hr = S_OK; } // // Allocate returned name. // if (pwszAccountName != NULL) { LPWSTR pwszAccountNameCopy; pwszAccountNameCopy = (LPWSTR)CoTaskMemAlloc( (s_wcslen(pwszAccountName) + 1) * sizeof(WCHAR)); if (pwszAccountNameCopy == NULL) { return(E_OUTOFMEMORY); } s_wcscpy(pwszAccountNameCopy, pwszAccountName); *ppwszAccountName = pwszAccountNameCopy; } return(hr); #else return(SCHED_E_NO_SECURITY_SERVICES); #endif // !defined(_CHICAGO) } //+---------------------------------------------------------------------------- // // Member: CJob::IPersistFile::Save // // Synopsis: Save job properties to the job object. Upon successful save, // if account credentials have been specified, set them via // RPC to the service. // // Arguments: [pwszFileName] - if null, save to the previously loaded file. // [fRemember] - if TRUE, the object becomes associated with // the new filename. // // Notes: This member must now be split into two versions with the // addition of security: one for the .dll in // sched\client\job.cxx, and for the .exe in // sched\svc_core\job.cxx. This was necessary as Save now // includes client-side rpc code. A single version of this // member would require the client-side rpc code to be included // in the service. // // All OLE32 strings are UNICODE, including the filename passed // in the IPersistFile methods. On Win9x, all file names must // be in ANSI strings, thus the conversion and call to SaveP. // //----------------------------------------------------------------------------- STDMETHODIMP CJob::Save(LPCOLESTR pwszFileName, BOOL fRemember) { HRESULT hr = S_OK; #if defined(UNICODE) // // Always save fixed and variable length data, but Never alter the running // instance count from the COM interface method. // hr = SaveP(pwszFileName, fRemember, SAVEP_VARIABLE_LENGTH_DATA); #else CHAR szFileName[MAX_PATH + 1]; if (pwszFileName != NULL) // If filename non-null, convert to ANSI { hr = UnicodeToAnsi(szFileName, pwszFileName, MAX_PATH + 1); if (FAILED(hr)) { return STG_E_INVALIDNAME; } } hr = SaveP(pwszFileName != NULL ? szFileName : NULL, fRemember, SAVEP_VARIABLE_LENGTH_DATA); #endif if (FAILED(hr)) { return(hr); } // // If nested folders are allowed in the future, add code something // like this: // // // if (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) // { // // // // Create folders as needed // // // hr = CreateFolders(pwszFileName, TRUE); // if (FAILED(hr)) // { // ERR_OUT("CJob::Save: CreateFolders", hr); // return hr; // } // // // // Try again // // // hr = pJob->SaveP(pwszFileName, fRemember, SAVEP_VARIABLE_LENGTH_DATA); // } // // // This operation is not supported locally on Win95, and for the first // release of the scheduling agent, neither remotely from Win95 to NT. // #if !defined(_CHICAGO_) // // Now that job changes are completely saved, set security information, // if specified. This order is important as the application name is tied // to the credentials for security reasons. If the application changes, // the existing credentials are invalidated. // // ** Important ** Maintain file save, security setting order! // if (IsFlagSet(JOB_I_FLAG_SET_ACCOUNT_INFO)) { // // RPC to the server local to this job to fetch the account name // associated with this job. // // First, figure out if this is a remote job. If so, fetch the server // name on which the job resides. // // Also, if this code is executing on Win95, and the file name passed // is NULL, the ANSI private filename data must be converted to // unicode. Note, CJob::SaveP checks if m_ptszFileName is NULL. The // member fails if this is the case. // WCHAR wszUNCPath[MAX_PATH + 1]; WCHAR * pwszFileNameLocal; WCHAR * pwszServerName; #if !defined(UNICODE) WCHAR wszFileName[MAX_PATH + 1] = L""; #endif // UNICODE if (pwszFileName == NULL) { #if !defined(UNICODE) hr = AnsiToUnicode(wszFileName, m_ptszFileName, MAX_PATH + 1); if (FAILED(hr)) { return(hr); } pwszFileNameLocal = wszFileName; #else pwszFileNameLocal = m_ptszFileName; #endif // UNICODE } else { pwszFileNameLocal = (WCHAR *)pwszFileName; } // // Fetch the server name associated with the network path. If the path // is local, the server name returned will be NULL. // hr = GetServerNameFromPath(pwszFileNameLocal, (MAX_PATH + 1) * sizeof(WCHAR), wszUNCPath, &pwszServerName); if (FAILED(hr)) { return(hr); } #if defined(_CHICAGO_) // // Local security operations are not supported on Win95. // if (pwszServerName == NULL) { return(SCHED_E_NO_SECURITY_SERVICES); } #endif // _CHICAGO_ // // RPC to the service to set the account information. // // First, isolate the relative job name from the remaining path. // WCHAR * pwszRelativeFileName; if (pwszFileNameLocal != NULL) { pwszRelativeFileName = wcsrchr(pwszFileNameLocal, L'\\'); if (pwszRelativeFileName != NULL) { pwszRelativeFileName++; } else { pwszRelativeFileName = pwszFileNameLocal; } } RpcTryExcept { // // Note: We pass the flags via RPC in order to let // the server side do the access checks for the NULL // password case. These checks could technically be // done on the client side, but it's more convenient // (and smaller codesize) to do it this way // hr = SASetAccountInformation(pwszServerName, pwszRelativeFileName, m_pAccountInfo->pwszAccount, m_pAccountInfo->pwszPassword, m_rgFlags); } RpcExcept(1) { DWORD Status = RpcExceptionCode(); schDebugOut((DEB_ERROR, "SetAccountInformation exception(0x%x)\n", Status)); hr = SchedMapRpcError(Status); } RpcEndExcept; this->ClearFlag(JOB_I_FLAG_SET_ACCOUNT_INFO); // // NB : After successful save of the security information, the // cached values are reset. // ResetAccountInfo(m_pAccountInfo); delete m_pAccountInfo; m_pAccountInfo = NULL; } #endif // !defined(_CHICAGO_) return hr; } // // This operation is not supported locally on Win95, and for the first // release of the scheduling agent, neither remotely from Win95 to NT. // #if !defined(_CHICAGO_) //+---------------------------------------------------------------------------- // // Function: ResetAccountInfo // // Synopsis: Simple helper to zero the password and deallocate struct // JOB_ACCOUNT_INFO fields. // // Arguments: [pAccountInfo] -- Account info struct to reset. // // Returns: None. // // Notes: None. // //----------------------------------------------------------------------------- void ResetAccountInfo(PJOB_ACCOUNT_INFO pAccountInfo) { delete pAccountInfo->pwszAccount; pAccountInfo->pwszAccount = NULL; if (pAccountInfo->pwszPassword != NULL) { ZERO_PASSWORD(pAccountInfo->pwszPassword); delete pAccountInfo->pwszPassword; pAccountInfo->pwszPassword = NULL; } } #endif // !defined(_CHICAGO_)