windows-nt/Source/XPSP1/NT/admin/services/sched/client/job.cxx

662 lines
18 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//____________________________________________________________________________
//
// 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_)