You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
541 lines
16 KiB
541 lines
16 KiB
//____________________________________________________________________________
|
|
//
|
|
// 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
|
|
|
|
#include "network.hxx"
|
|
#include "misc.hxx"
|
|
#include "job_cls.hxx"
|
|
#include "debug.hxx"
|
|
#include "defines.hxx"
|
|
#include "SASecRPC.h" // Get/SetAccountInformation RPC definition.
|
|
#include <StrSafe.h>
|
|
|
|
typedef DWORD (WINAPI * PWNETGETUNIVERSALNAMEW)(LPCWSTR, DWORD, LPVOID,
|
|
LPDWORD);
|
|
|
|
PWNETGETUNIVERSALNAMEW gpWNetGetUniversalNameW = NULL;
|
|
|
|
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.
|
|
//
|
|
|
|
void ResetAccountInfo(PJOB_ACCOUNT_INFO pAccountInfo);
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
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;
|
|
size_t acctLength = wcslen(pwszAccountName) + 1;
|
|
pAccountInfo->pwszAccount = new WCHAR[acctLength];
|
|
|
|
if (pAccountInfo->pwszAccount != NULL)
|
|
{
|
|
StringCchCopy(pAccountInfo->pwszAccount, acctLength, pwszAccountName);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (pwszPassword != NULL)
|
|
{
|
|
size_t pwLength = wcslen(pwszPassword) + 1;
|
|
pAccountInfo->pwszPassword = new WCHAR[pwLength];
|
|
|
|
if (pAccountInfo->pwszPassword != NULL)
|
|
{
|
|
StringCchCopy(pAccountInfo->pwszPassword, pwLength, 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);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
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;
|
|
|
|
pwszFileName = m_ptszFileName;
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
size_t pwLength = (wcslen(pwszAccountName) + 1);
|
|
pwszAccountNameCopy = (LPWSTR)CoTaskMemAlloc(
|
|
pwLength * sizeof(WCHAR));
|
|
|
|
if (pwszAccountNameCopy == NULL)
|
|
{
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
StringCchCopy(pwszAccountNameCopy, pwLength, pwszAccountName);
|
|
*ppwszAccountName = pwszAccountNameCopy;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CJob::Save(LPCOLESTR pwszFileName, BOOL fRemember)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// Always save fixed and variable length data, but Never alter the running
|
|
// instance count from the COM interface method.
|
|
//
|
|
|
|
hr = SaveWithRetry(pwszFileName, fRemember, SAVEP_VARIABLE_LENGTH_DATA);
|
|
if (FAILED(hr))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
WCHAR wszUNCPath[MAX_PATH + 1];
|
|
WCHAR * pwszFileNameLocal;
|
|
WCHAR * pwszServerName;
|
|
|
|
if (pwszFileName == NULL)
|
|
{
|
|
pwszFileNameLocal = m_ptszFileName;
|
|
}
|
|
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);
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
}
|