windows-nt/Source/XPSP1/NT/net/mmc/tapi/servpp.cpp
2020-09-26 16:20:57 +08:00

1365 lines
38 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/
/*
Servpp.h
Server properties implementation file
FILE HISTORY:
*/
#include "stdafx.h"
#include "Servpp.h"
#include "server.h"
#include "service.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const DWORD c_dwChangableFlagMask =
TAPISERVERCONFIGFLAGS_ENABLESERVER |
TAPISERVERCONFIGFLAGS_SETACCOUNT |
TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS;
const TCHAR szPasswordNull[] = _T(" "); // Empty password
BOOL
IsLocalSystemAccount(LPCTSTR pszAccount)
{
BOOL bRet = FALSE;
DWORD dwSidSize = 128;
DWORD dwDomainNameSize = 128;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID pLocalSid = NULL;
PSID pLocalServiceSid = NULL;
PSID pNetworkServiceSid = NULL;
PSID accountSid = NULL;
SID_NAME_USE SidType;
LPWSTR pwszDomainName;
do
{
// Attempt to allocate a buffer for the SID. Note that apparently in the
// absence of any error theData->m_Sid is freed only when theData goes
// out of scope.
accountSid = LocalAlloc( LMEM_FIXED, dwSidSize );
pwszDomainName = (LPWSTR) LocalAlloc( LMEM_FIXED, dwDomainNameSize * sizeof(WCHAR) );
// Was space allocated for the SID and domain name successfully?
if ( accountSid == NULL || pwszDomainName == NULL )
{
if ( accountSid != NULL )
{
LocalFree( accountSid );
accountSid = NULL;
}
if ( pwszDomainName != NULL )
{
LocalFree( pwszDomainName );
}
goto ExitHere;
}
// Attempt to Retrieve the SID and domain name. If LookupAccountName failes
// because of insufficient buffer size(s) dwSidSize and dwDomainNameSize
// will be set correctly for the next attempt.
if (LookupAccountName (NULL,
pszAccount,
accountSid,
&dwSidSize,
pwszDomainName,
&dwDomainNameSize,
&SidType ))
{
break;
}
if (ERROR_INSUFFICIENT_BUFFER != GetLastError ())
{
goto ExitHere;
}
// domain name isn't needed at any time
LocalFree (pwszDomainName);
LocalFree (accountSid);
} while ( TRUE );
if (!AllocateAndInitializeSid (
&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&pLocalSid) ||
!AllocateAndInitializeSid (
&NtAuthority,
1,
SECURITY_LOCAL_SERVICE_RID,
0, 0, 0, 0, 0, 0, 0,
&pLocalServiceSid) ||
!AllocateAndInitializeSid (
&NtAuthority,
1,
SECURITY_NETWORK_SERVICE_RID,
0, 0, 0, 0, 0, 0, 0,
&pNetworkServiceSid)
)
{
goto ExitHere;
}
if (EqualSid(pLocalSid, accountSid) ||
EqualSid(pLocalServiceSid, accountSid) ||
EqualSid(pNetworkServiceSid, accountSid))
{
bRet = TRUE;
}
ExitHere:
if (NULL != pwszDomainName)
{
LocalFree (pwszDomainName);
}
if (NULL != accountSid)
{
LocalFree (accountSid);
}
if (NULL != pLocalSid)
{
FreeSid(pLocalSid);
}
if (NULL != pLocalServiceSid)
{
FreeSid (pLocalServiceSid);
}
if (NULL != pNetworkServiceSid)
{
FreeSid (pNetworkServiceSid);
}
return bRet;
}
/////////////////////////////////////////////////////////////////////////////
//
// CServerProperties holder
//
/////////////////////////////////////////////////////////////////////////////
CServerProperties::CServerProperties
(
ITFSNode * pNode,
IComponentData * pComponentData,
ITFSComponentData * pTFSCompData,
ITapiInfo * pTapiInfo,
LPCTSTR pszSheetName,
BOOL fTapiInfoLoaded
) : CPropertyPageHolderBase(pNode, pComponentData, pszSheetName),
m_fTapiInfoLoaded(fTapiInfoLoaded)
{
//ASSERT(pFolderNode == GetContainerNode());
m_bAutoDeletePages = FALSE; // we have the pages as embedded members
AddPageToList((CPropertyPageBase*) &m_pageSetup);
AddPageToList((CPropertyPageBase*) &m_pageRefresh);
Assert(pTFSCompData != NULL);
m_spTFSCompData.Set(pTFSCompData);
m_spTapiInfo.Set(pTapiInfo);
m_hScManager = NULL;
m_paQSC = NULL;
m_pszServiceName = TAPI_SERVICE_NAME;
}
CServerProperties::~CServerProperties()
{
// Close the service control manager database
if (m_hScManager != NULL)
{
(void)::CloseServiceHandle(m_hScManager);
}
// Free the allocated pointers
if (m_paQSC)
delete m_paQSC;
RemovePageFromList((CPropertyPageBase*) &m_pageSetup, FALSE);
RemovePageFromList((CPropertyPageBase*) &m_pageRefresh, FALSE);
}
BOOL
CServerProperties::FInit()
{
// get the service account information here
SC_HANDLE hService = NULL;
DWORD cbBytesNeeded = 0;
BOOL fSuccess = TRUE;
BOOL f;
DWORD dwErr;
m_uFlags = 0;
if (!FOpenScManager())
{
// Unable to open service control database
return FALSE;
}
/*
** Open service with querying access-control
*/
hService = ::OpenService(m_hScManager,
m_pszServiceName,
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
if (hService == NULL)
{
TapiMessageBox(::GetLastError());
return FALSE;
}
/*
** Query the service status
*/
Trace1("# QueryServiceStatus(%s)...\n", m_pszServiceName);
f = ::QueryServiceStatus(hService, OUT &m_SS);
if (f)
{
//m_uFlags |= mskfValidSS;
}
else
{
::TapiMessageBox(::GetLastError());
fSuccess = FALSE;
}
/*
** Query the service config
*/
Trace1("# QueryServiceConfig(%s)...\n", m_pszServiceName);
f = ::QueryServiceConfig(hService,
NULL,
0,
OUT &cbBytesNeeded); // Compute how many bytes we need to allocate
cbBytesNeeded += 100; // Add extra bytes (just in case)
delete m_paQSC; // Free previously allocated memory (if any)
m_paQSC = (QUERY_SERVICE_CONFIG *) new BYTE[cbBytesNeeded];
f = ::QueryServiceConfig(hService,
OUT m_paQSC,
cbBytesNeeded,
OUT &cbBytesNeeded);
if (f)
{
m_strServiceDisplayName = m_paQSC->lpDisplayName;
m_strLogOnAccountName = m_paQSC->lpServiceStartName;
}
else
{
::TapiMessageBox(::GetLastError());
fSuccess = FALSE;
}
VERIFY(::CloseServiceHandle(hService));
return fSuccess;
}
/////////////////////////////////////////////////////////////////////
// FOpenScManager()
//
// Open the service control manager database (if not already opened).
// The idea for such a function is to recover from a broken connection.
//
// Return TRUE if the service control database was opened successfully,
// othersise false.
//
BOOL
CServerProperties::FOpenScManager()
{
if (m_hScManager == NULL)
{
m_hScManager = ::OpenSCManager(m_strMachineName,
NULL,
SC_MANAGER_CONNECT);
}
if (m_hScManager == NULL)
{
TapiMessageBox(::GetLastError());
return FALSE;
}
return TRUE;
} // CServicePropertyData::FOpenScManager()
BOOL
CServerProperties::FUpdateServiceInfo(LPCTSTR pszName, LPCTSTR pszPassword, DWORD dwStartType)
{
SC_HANDLE hService = NULL;
BOOL fSuccess = TRUE;
BOOL f;
DWORD dwServiceType = 0;
Trace1("INFO: Updating data for service %s...\n", (LPCTSTR)m_pszServiceName);
// Re-open service control manager (in case it was closed)
if (!FOpenScManager())
{
return FALSE;
}
/*
** Open service with write access
**
** CODEWORK Could provide a more specific error message
** if SERVICE_CHANGE_CONFIG is available but not SERVICE_START
*/
hService = ::OpenService(m_hScManager,
m_pszServiceName,
SERVICE_CHANGE_CONFIG);
if (hService == NULL)
{
TapiMessageBox(::GetLastError());
return FALSE;
}
Trace1("# ChangeServiceConfig(%s)...\n", m_pszServiceName);
if (pszName)
{
if (IsLocalSystemAccount(pszName))
{
pszPassword = szPasswordNull;
}
dwServiceType = m_paQSC->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
}
else
{
dwServiceType = SERVICE_NO_CHANGE;
}
f = ::ChangeServiceConfig(hService, // Handle to service
dwServiceType, // Type of service
dwStartType, // When/How to start service
SERVICE_NO_CHANGE, // dwErrorControl - severity if service fails to start
NULL, // Pointer to service binary file name
NULL, // lpLoadOrderGroup - pointer to load ordering group name
NULL, // lpdwTagId - pointer to variable to get tag identifier
NULL, // lpDependencies - pointer to array of dependency names
pszName, // Pointer to account name of service
pszPassword, // Pointer to password for service account
m_strServiceDisplayName);
if (!f)
{
DWORD dwErr = ::GetLastError();
Assert(dwErr != ERROR_SUCCESS);
Trace2("ERR: ChangeServiceConfig(%s) failed. err= %u.\n", m_pszServiceName, dwErr);
TapiMessageBox(dwErr);
fSuccess = FALSE;
}
else
{
m_strLogOnAccountName = pszName;
// if pszName is null, we aren't changing the account info, so don't check
// the logon as service info
if (pszName && !IsLocalSystemAccount(pszName))
{
/*
** Make sure there is an LSA account with POLICY_MODE_SERVICE privilege
** This function reports its own errors, failure is only advisory
*/
FCheckLSAAccount();
}
}
VERIFY(::CloseServiceHandle(hService));
return fSuccess;
}
//Check if the user has the write access on service config info
BOOL
CServerProperties::FHasServiceControl()
{
BOOL fRet = FALSE;
if (FIsTapiInfoLoaded())
{
fRet = m_spTapiInfo->FHasServiceControl();
}
else
{
if (!FOpenScManager())
{
fRet = FALSE;
}
else
{
SC_HANDLE hService = NULL;
hService = ::OpenService(m_hScManager,
m_pszServiceName,
SERVICE_CHANGE_CONFIG);
fRet = (hService != NULL);
if (hService)
{
VERIFY(::CloseServiceHandle(hService));
}
}
}
return fRet;
}
/////////////////////////////////////////////////////////////////////////////
// CServerPropRefresh property page
IMPLEMENT_DYNCREATE(CServerPropRefresh, CPropertyPageBase)
CServerPropRefresh::CServerPropRefresh() : CPropertyPageBase(CServerPropRefresh::IDD)
{
//{{AFX_DATA_INIT(CServerPropRefresh)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CServerPropRefresh::~CServerPropRefresh()
{
}
void CServerPropRefresh::DoDataExchange(CDataExchange* pDX)
{
CPropertyPageBase::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CServerPropRefresh)
DDX_Control(pDX, IDC_EDIT_MINUTES, m_editMinutes);
DDX_Control(pDX, IDC_EDIT_HOURS, m_editHours);
DDX_Control(pDX, IDC_SPIN_MINUTES, m_spinMinutes);
DDX_Control(pDX, IDC_SPIN_HOURS, m_spinHours);
DDX_Control(pDX, IDC_CHECK_ENABLE_STATS, m_checkEnableStats);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CServerPropRefresh, CPropertyPageBase)
//{{AFX_MSG_MAP(CServerPropRefresh)
ON_BN_CLICKED(IDC_CHECK_ENABLE_STATS, OnCheckEnableStats)
ON_EN_KILLFOCUS(IDC_EDIT_HOURS, OnKillfocusEditHours)
ON_EN_KILLFOCUS(IDC_EDIT_MINUTES, OnKillfocusEditMinutes)
ON_EN_CHANGE(IDC_EDIT_HOURS, OnChangeEditHours)
ON_EN_CHANGE(IDC_EDIT_MINUTES, OnChangeEditMinutes)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerPropRefresh message handlers
BOOL CServerPropRefresh::OnInitDialog()
{
CPropertyPageBase::OnInitDialog();
m_spinHours.SetRange(0, AUTO_REFRESH_HOURS_MAX);
m_spinMinutes.SetRange(0, AUTO_REFRESH_MINUTES_MAX);
m_checkEnableStats.SetCheck(m_bAutoRefresh);
// update the refresh interval
int nHours, nMinutes;
DWORD dwRefreshInterval = m_dwRefreshInterval;
nHours = dwRefreshInterval / MILLISEC_PER_HOUR;
dwRefreshInterval -= nHours * MILLISEC_PER_HOUR;
nMinutes = dwRefreshInterval / MILLISEC_PER_MINUTE;
dwRefreshInterval -= nMinutes * MILLISEC_PER_MINUTE;
m_spinHours.SetPos(nHours);
m_spinMinutes.SetPos(nMinutes);
m_editHours.LimitText(2);
m_editMinutes.LimitText(2);
// set the button states
UpdateButtons();
SetDirty(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CServerPropRefresh::UpdateButtons()
{
int nCheck = m_checkEnableStats.GetCheck();
GetDlgItem(IDC_EDIT_HOURS)->EnableWindow(nCheck != 0);
GetDlgItem(IDC_EDIT_MINUTES)->EnableWindow(nCheck != 0);
GetDlgItem(IDC_SPIN_HOURS)->EnableWindow(nCheck != 0);
GetDlgItem(IDC_SPIN_MINUTES)->EnableWindow(nCheck != 0);
}
void CServerPropRefresh::OnCheckEnableStats()
{
SetDirty(TRUE);
UpdateButtons();
}
void CServerPropRefresh::OnKillfocusEditHours()
{
}
void CServerPropRefresh::OnKillfocusEditMinutes()
{
}
void CServerPropRefresh::OnChangeEditHours()
{
ValidateHours();
SetDirty(TRUE);
}
void CServerPropRefresh::OnChangeEditMinutes()
{
ValidateMinutes();
SetDirty(TRUE);
}
void CServerPropRefresh::ValidateHours()
{
CString strValue;
int nValue;
if (m_editHours.GetSafeHwnd() != NULL)
{
m_editHours.GetWindowText(strValue);
if (!strValue.IsEmpty())
{
nValue = _ttoi(strValue);
if ((nValue >= 0) &&
(nValue <= AUTO_REFRESH_HOURS_MAX))
{
// everything is good
return;
}
if (nValue > AUTO_REFRESH_HOURS_MAX)
nValue = AUTO_REFRESH_HOURS_MAX;
else
if (nValue < 0)
nValue = 0;
// set the new value and beep
CString strText;
LPTSTR pBuf = strText.GetBuffer(5);
_itot(nValue, pBuf, 10);
strText.ReleaseBuffer();
MessageBeep(MB_ICONEXCLAMATION);
m_editHours.SetWindowText(strText);
m_editHours.SetSel(0, -1);
m_editHours.SetFocus();
}
}
}
void CServerPropRefresh::ValidateMinutes()
{
CString strValue;
int nValue;
if (m_editMinutes.GetSafeHwnd() != NULL)
{
m_editMinutes.GetWindowText(strValue);
if (!strValue.IsEmpty())
{
nValue = _ttoi(strValue);
if ((nValue >= 0) &&
(nValue <= AUTO_REFRESH_MINUTES_MAX))
{
// everything is good
return;
}
if (nValue > AUTO_REFRESH_MINUTES_MAX)
nValue = AUTO_REFRESH_MINUTES_MAX;
else
if (nValue < 0)
nValue = 0;
CString strText;
LPTSTR pBuf = strText.GetBuffer(5);
_itot(nValue, pBuf, 10);
strText.ReleaseBuffer();
MessageBeep(MB_ICONEXCLAMATION);
m_editMinutes.SetWindowText(strText);
m_editMinutes.SetSel(0, -1);
m_editMinutes.SetFocus();
}
}
}
BOOL CServerPropRefresh::OnApply()
{
if (!IsDirty())
return TRUE;
UpdateData();
m_bAutoRefresh = (m_checkEnableStats.GetCheck() == 1) ? TRUE : FALSE;
int nHours = m_spinHours.GetPos();
int nMinutes = m_spinMinutes.GetPos();
m_dwRefreshInterval = nHours * MILLISEC_PER_HOUR;
m_dwRefreshInterval += nMinutes * MILLISEC_PER_MINUTE;
if (m_bAutoRefresh && m_dwRefreshInterval == 0)
{
CString strMessage;
AfxMessageBox(IDS_ERR_AUTO_REFRESH_ZERO);
m_editHours.SetSel(0, -1);
m_editHours.SetFocus();
return FALSE;
}
BOOL bRet = CPropertyPageBase::OnApply();
if (bRet == FALSE)
{
// Something bad happened... grab the error code
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
::TapiMessageBox(GetHolder()->GetError());
}
return bRet;
}
BOOL CServerPropRefresh::OnPropertyChange(BOOL bScope, LONG_PTR *ChangeMask)
{
SPITFSNode spNode;
CTapiServer * pServer;
DWORD dwError;
// do stuff here.
BEGIN_WAIT_CURSOR;
spNode = GetHolder()->GetNode();
pServer = GETHANDLER(CTapiServer, spNode);
pServer->SetAutoRefresh(spNode, m_bAutoRefresh, m_dwRefreshInterval);
SPITFSNodeMgr spNodeMgr;
SPITFSNode spRootNode;
spNode->GetNodeMgr(&spNodeMgr);
spNodeMgr->GetRootNode(&spRootNode);
spRootNode->SetData(TFS_DATA_DIRTY, TRUE);
END_WAIT_CURSOR;
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CServerPropSetup property page
IMPLEMENT_DYNCREATE(CServerPropSetup, CPropertyPageBase)
CServerPropSetup::CServerPropSetup() : CPropertyPageBase(CServerPropSetup::IDD)
{
//{{AFX_DATA_INIT(CServerPropSetup)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_dwNewFlags = 0;
}
CServerPropSetup::~CServerPropSetup()
{
}
void CServerPropSetup::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CServerPropSetup)
DDX_Control(pDX, IDC_LIST_ADMINS, m_listAdmins);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CServerPropSetup, CPropertyPageBase)
//{{AFX_MSG_MAP(CServerPropSetup)
ON_BN_CLICKED(IDC_BUTTON_ADD_ADMIN, OnButtonAdd)
ON_BN_CLICKED(IDC_BUTTON_CHOOSE_USER, OnButtonChooseUser)
ON_BN_CLICKED(IDC_BUTTON_REMOVE_ADMIN, OnButtonRemove)
ON_BN_CLICKED(IDC_CHECK_ENABLE_SERVER, OnCheckEnableServer)
ON_EN_CHANGE(IDC_EDIT_NAME, OnChangeEditName)
ON_EN_CHANGE(IDC_EDIT_PASSWORD, OnChangeEditPassword)
ON_LBN_SELCHANGE(IDC_LIST_ADMINS, OnSelchangeListAdmins)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerPropSetup message handlers
BOOL CServerPropSetup::OnInitDialog()
{
SPITapiInfo spTapiInfo;
CString strName;
HRESULT hr = hrOK;
CPropertyPageBase::OnInitDialog();
CServerProperties * pServerProp = (CServerProperties * ) GetHolder();
pServerProp->GetTapiInfo(&spTapiInfo);
Assert(spTapiInfo);
BOOL fIsNTS = TRUE;
if (pServerProp->FIsServiceRunning())
{
fIsNTS = spTapiInfo->IsServer();
hr = spTapiInfo->GetConfigInfo(&m_tapiConfigInfo);
if (FAILED(hr))
{
Panic1("ServerPropSetup - GetConfigInfo failed! %x", hr);
}
// update the checkbox
((CButton *) GetDlgItem(IDC_CHECK_ENABLE_SERVER))->SetCheck(spTapiInfo->IsTapiServer());
// now update any TAPI administrators
for (int i = 0; i < m_tapiConfigInfo.m_arrayAdministrators.GetSize(); i++)
{
((CListBox *) GetDlgItem(IDC_LIST_ADMINS))->AddString(m_tapiConfigInfo.m_arrayAdministrators[i].m_strName);
}
}
else
{
// check to see if the machine is NTS
TFSIsNTServer(pServerProp->m_strMachineName, &fIsNTS);
}
if (fIsNTS)
{
// fill in the username and password
strName = pServerProp->GetServiceAccountName();
GetDlgItem(IDC_EDIT_NAME)->SetWindowText(strName);
GetDlgItem(IDC_EDIT_PASSWORD)->SetWindowText(szPasswordNull);
m_dwNewFlags = TAPISERVERCONFIGFLAGS_ISSERVER;
}
else
{
m_dwNewFlags = 0;
}
EnableButtons(fIsNTS);
m_fRestartService = FALSE;
m_dwInitFlags = m_tapiConfigInfo.m_dwFlags;
SetDirty(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CServerPropSetup::OnButtonAdd()
{
CGetUsers getUsers(TRUE);
if (!getUsers.GetUsers(GetSafeHwnd()))
return;
for (int nCount = 0; nCount < getUsers.GetSize(); nCount++)
{
CUserInfo userTemp;
userTemp = getUsers[nCount];
BOOL fDuplicate = FALSE;
for (int i = 0; i < m_tapiConfigInfo.m_arrayAdministrators.GetSize(); i++)
{
if (m_tapiConfigInfo.m_arrayAdministrators[i].m_strName.CompareNoCase(userTemp.m_strName) == 0)
{
fDuplicate = TRUE;
break;
}
}
if (!fDuplicate)
{
// add to the array
int nIndex = (int)m_tapiConfigInfo.m_arrayAdministrators.Add(userTemp);
// now add to the listbox
m_listAdmins.AddString(m_tapiConfigInfo.m_arrayAdministrators[nIndex].m_strName);
}
else
{
// tell the user we're not adding this to the list
CString strMessage;
AfxFormatString1(strMessage, IDS_ADMIN_ALREADY_IN_LIST, userTemp.m_strName);
AfxMessageBox(strMessage);
}
SetDirty(TRUE);
}
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS;
EnableButtons();
}
void CServerPropSetup::OnButtonRemove()
{
CString strSelectedName;
int nCurSel = m_listAdmins.GetCurSel();
m_listAdmins.GetText(nCurSel, strSelectedName);
// remove from the list
for (int i = 0; i < m_tapiConfigInfo.m_arrayAdministrators.GetSize(); i++)
{
if (strSelectedName.Compare(m_tapiConfigInfo.m_arrayAdministrators[i].m_strName) == 0)
{
// found it. remove from the list
m_tapiConfigInfo.m_arrayAdministrators.RemoveAt(i);
break;
}
}
// now remove from the list box
m_listAdmins.DeleteString(nCurSel);
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS;
SetDirty(TRUE);
EnableButtons();
}
void CServerPropSetup::OnButtonChooseUser()
{
CGetUsers getUsers;
if (!getUsers.GetUsers(GetSafeHwnd()))
return;
if (0 == getUsers.GetSize())
return;
CUserInfo userTemp;
userTemp = getUsers[0];
GetDlgItem(IDC_EDIT_NAME)->SetWindowText(userTemp.m_strName);
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
SetDirty(TRUE);
EnableButtons();
}
void CServerPropSetup::OnCheckEnableServer()
{
if (((CButton *) GetDlgItem(IDC_CHECK_ENABLE_SERVER))->GetCheck())
{
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_ENABLESERVER;
}
else
{
m_dwNewFlags &= ~TAPISERVERCONFIGFLAGS_ENABLESERVER;
}
EnableButtons ();
SetDirty(TRUE);
}
void CServerPropSetup::OnChangeEditName()
{
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
SetDirty(TRUE);
}
void CServerPropSetup::OnChangeEditPassword()
{
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
m_fRestartService = TRUE;
SetDirty(TRUE);
}
void CServerPropSetup::OnSelchangeListAdmins()
{
EnableButtons();
}
void CServerPropSetup::EnableButtons(BOOL fIsNtServer)
{
BOOL fServiceRunning = ((CServerProperties *) GetHolder())->FIsServiceRunning();
//if we are unable to get the write access to tapisrv service, we need to disable
// some controls
BOOL fHasServiceControl = ((CServerProperties *) GetHolder())->FHasServiceControl();
//We enable the admin controls only if we sucessfully loaded the tapi info
BOOL fTapiInfoLoaded = ((CServerProperties *) GetHolder())->FIsTapiInfoLoaded();
BOOL fIsAdmin = ((CServerProperties *) GetHolder())->FIsAdmin();
// if this isn't an NT server, disable all controls
if (!fIsNtServer)
fServiceRunning = FALSE;
//Enable the Admin controls only if
//(1) the service is running
//(2) successfully loaded the tapi config info
//(3) the user is a machine admin or tapi admin
BOOL fEnableAdminControls = fServiceRunning && fTapiInfoLoaded && fIsAdmin;
// enable the admin controls on
GetDlgItem(IDC_STATIC_ADMINS)->EnableWindow(fEnableAdminControls);
GetDlgItem(IDC_STATIC_NOTE)->EnableWindow(fEnableAdminControls);
GetDlgItem(IDC_STATIC_LISTBOX)->EnableWindow(fEnableAdminControls);
GetDlgItem(IDC_BUTTON_ADD_ADMIN)->EnableWindow(fEnableAdminControls);
GetDlgItem(IDC_BUTTON_REMOVE_ADMIN)->EnableWindow(fEnableAdminControls);
GetDlgItem(IDC_LIST_ADMINS)->EnableWindow(fEnableAdminControls);
//If the user is not admin, then they don't have ServiceControl write access
//So fHasServiceControl covers fIsAdmin
GetDlgItem(IDC_CHECK_ENABLE_SERVER)->EnableWindow(fServiceRunning
&& fHasServiceControl
&& fTapiInfoLoaded);
// these should always be available if we have service control access
// and we are running on server
GetDlgItem(IDC_STATIC_USERNAME)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_STATIC_PASSWORD)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_STATIC_ACCOUNT)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_BUTTON_CHOOSE_USER)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_EDIT_NAME)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_EDIT_PASSWORD)->EnableWindow(fIsNtServer && fHasServiceControl);
GetDlgItem(IDC_STATIC_ACCOUNT_INFO)->EnableWindow(fIsNtServer && fHasServiceControl);
if (fServiceRunning)
{
// enable the remove button if something is selected
BOOL fEnableRemove = m_listAdmins.GetCurSel() != LB_ERR;
//if we will disable the remove button and the remove button has the focus,
//we should change focus to the next control
CWnd * pwndRemove = GetDlgItem(IDC_BUTTON_REMOVE_ADMIN);
if (!fEnableRemove && GetFocus() == pwndRemove)
{
NextDlgCtrl();
}
pwndRemove->EnableWindow(fEnableRemove);
}
}
BOOL CServerPropSetup::OnApply()
{
CString strAccount, strPassword;
BOOL fUpdateAccount = FALSE;
BOOL fUpdateTapiServer = FALSE;
BOOL bRet = TRUE;
BOOL bWasServer, bToBeServer;
DWORD dwStartType = SERVICE_NO_CHANGE;
if (!IsDirty())
return bRet;
CServerProperties * pServerProp = (CServerProperties * ) GetHolder();
UpdateData();
// Check to see if there is any change on enabling server
// or user account name, that requires service restarting
if (!m_fRestartService)
{
bWasServer = m_dwInitFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER;
bToBeServer = ((CButton *) GetDlgItem(IDC_CHECK_ENABLE_SERVER))->GetCheck();
if (bWasServer && !bToBeServer || !bWasServer && bToBeServer)
{
m_fRestartService = TRUE;
}
if (m_dwNewFlags & TAPISERVERCONFIGFLAGS_SETACCOUNT)
{
GetDlgItem(IDC_EDIT_NAME)->GetWindowText(strAccount);
if (strAccount.CompareNoCase(pServerProp->GetServiceAccountName()) != 0)
{
m_fRestartService = TRUE;
}
else
{
m_dwNewFlags &= ~TAPISERVERCONFIGFLAGS_SETACCOUNT;
}
}
}
// if the account information has changed, the update the info struct now
if (m_dwNewFlags & TAPISERVERCONFIGFLAGS_SETACCOUNT)
{
GetDlgItem(IDC_EDIT_NAME)->GetWindowText(strAccount);
GetDlgItem(IDC_EDIT_PASSWORD)->GetWindowText(strPassword);
// verify that the user is an admin on the machine
if (!IsLocalSystemAccount(strAccount))
{
DWORD dwErr;
BOOL fIsAdmin;
CString strMessage;
dwErr = ::IsAdmin(pServerProp->m_strMachineName, strAccount, strPassword, &fIsAdmin);
if (!fIsAdmin)
{
AfxFormatString1(strMessage, IDS_ERR_USER_NOT_ADMIN, pServerProp->m_strMachineName);
AfxMessageBox(strMessage);
GetDlgItem(IDC_EDIT_NAME)->SetFocus();
((CEdit *) GetDlgItem(IDC_EDIT_NAME))->SetSel(0, -1);
return FALSE;
}
}
// clear the flag so we don't use the TAPI MMC APIs to set this
m_dwNewFlags &= ~TAPISERVERCONFIGFLAGS_SETACCOUNT;
fUpdateAccount = TRUE;
}
// if we are changing the server state or admin stuff then
if (((CButton *) GetDlgItem(IDC_CHECK_ENABLE_SERVER))->GetCheck())
{
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_ENABLESERVER;
}
// only update config information if it has changed
if ((pServerProp->FIsServiceRunning()) &&
(m_tapiConfigInfo.m_dwFlags != m_dwNewFlags))
{
// if we modify the tapi server status then we need to change the
// service statrt type as well.
if ((m_dwNewFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) &&
!(m_tapiConfigInfo.m_dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER))
{
fUpdateTapiServer = TRUE;
}
dwStartType = (m_dwNewFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
bRet = CPropertyPageBase::OnApply();
}
if (bRet == FALSE)
{
// Something bad happened... grab the error code
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
::TapiMessageBox(WIN32_FROM_HRESULT(GetHolder()->GetError()));
// restore the flag
if (fUpdateAccount)
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
}
else
{
m_dwNewFlags = TAPISERVERCONFIGFLAGS_ISSERVER;
if (fUpdateAccount || fUpdateTapiServer)
{
// do the account change
BEGIN_WAIT_CURSOR
LPCTSTR pszAccount = (fUpdateAccount) ? (LPCTSTR) strAccount : NULL;
LPCTSTR pszPassword = (fUpdateAccount) ? (LPCTSTR) strPassword : NULL;
bRet = pServerProp->FUpdateServiceInfo(pszAccount, pszPassword, dwStartType);
if (bRet)
{
/*$REVIEW
Tapisrv occupies a seperate house in NT server. It lives with the other
services on NT Professional Edition(workstation). We do not need to
sperate/merge services anymore. Users should not be allowed to change
account information from TAPI MMC on NT workstation(Disabled).
HRESULT hr;
// if the change was successful, update the svc host information
hr = UpdateSvcHostInfo(pServerProp->m_strMachineName, IsLocalSystemAccount(strAccount));
if (FAILED(hr))
{
// restore the flag
if (fUpdateAccount)
{
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
}
::TapiMessageBox(WIN32_FROM_HRESULT(hr));
return FALSE;
}
*/
}
else if (fUpdateAccount)
{
// set account failed, so set the flag again.
m_dwNewFlags |= TAPISERVERCONFIGFLAGS_SETACCOUNT;
}
END_WAIT_CURSOR
}
// if everything went OK and we changed something that requires a service restart then
// do ask the user if they want to do it now
if (bRet && m_fRestartService)
{
CString strText;
BOOL fServiceRunning = pServerProp->FIsServiceRunning();
::TFSIsServiceRunning(pServerProp->m_strMachineName,
TAPI_SERVICE_NAME,
&fServiceRunning);
if (fServiceRunning)
strText.LoadString(IDS_ACCOUNT_CHANGE_RESTART);
else
strText.LoadString(IDS_ACCOUNT_CHANGE_START);
// Tell the user the service needs to be restarted in order to make the changes
if (AfxMessageBox(strText, MB_YESNO) == IDYES)
{
if (RestartService() == ERROR_SUCCESS)
{
m_fRestartService = FALSE;
m_dwInitFlags = m_tapiConfigInfo.m_dwFlags;
}
}
}
}
if (!bRet)
SetDirty(TRUE);
return bRet;
}
BOOL CServerPropSetup::OnPropertyChange(BOOL bScope, LONG_PTR *ChangeMask)
{
SPITapiInfo spTapiInfo;
HRESULT hr = hrOK;
BOOL fServiceRunning = TRUE;
DWORD dwOldFlags;
DWORD dwErr = ERROR_SUCCESS;
CServerProperties * pServerProp = (CServerProperties * ) GetHolder();
pServerProp->GetTapiInfo(&spTapiInfo);
Assert(spTapiInfo);
// if the service isn't running, try to start it
//if (!pServerProp->FIsServiceRunning())
dwErr = ::TFSIsServiceRunning(pServerProp->m_strMachineName,
TAPI_SERVICE_NAME,
&fServiceRunning);
if (!fServiceRunning)
{
// service has stopped from under us. Return an error.
GetHolder()->SetError(HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE));
return FALSE;
}
// if everything is cool then make the changes
if (dwErr == ERROR_SUCCESS)
{
dwOldFlags = m_tapiConfigInfo.m_dwFlags;
//clear the changable bits in old flags
m_tapiConfigInfo.m_dwFlags &= ~c_dwChangableFlagMask;
//set the changable bits
m_tapiConfigInfo.m_dwFlags |= (m_dwNewFlags & c_dwChangableFlagMask);
hr = spTapiInfo->SetConfigInfo(&m_tapiConfigInfo);
//Bug 276787 We should clear the two write bits
m_tapiConfigInfo.m_dwFlags &= ~(TAPISERVERCONFIGFLAGS_SETACCOUNT |
TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS);
if (FAILED(hr))
{
GetHolder()->SetError(hr);
m_tapiConfigInfo.m_dwFlags = dwOldFlags;
}
}
return FALSE;
}
HRESULT CServerPropSetup::UpdateSvcHostInfo(LPCTSTR pszMachine, BOOL fLocalSystemAccount)
{
HRESULT hr = hrOK;
MULTI_QI qi;
SPIRemoteNetworkConfig spRemote;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
return hr;
}
if (IsLocalMachine(pszMachine))
{
hr = CoCreateInstance(CLSID_RemoteRouterConfig,
NULL,
CLSCTX_SERVER,
IID_IRemoteNetworkConfig,
(LPVOID *) &(qi.pItf));
}
else
{
COSERVERINFO csi;
qi.pIID = &IID_IRemoteNetworkConfig;
qi.pItf = NULL;
qi.hr = 0;
csi.dwReserved1 = 0;
csi.dwReserved2 = 0;
csi.pwszName = (LPWSTR) (LPCTSTR) pszMachine;
csi.pAuthInfo = NULL;
hr = CoCreateInstanceEx(CLSID_RemoteRouterConfig,
NULL,
CLSCTX_SERVER,
&csi,
1,
&qi);
}
Trace1("CServerPropSetup::UpdateSvcHostInfo - CoCreateInstance returned %lx\n", hr);
if (hr == S_OK)
{
CString strGroup;
strGroup = _T("Tapisrv");
spRemote = (IRemoteNetworkConfig *)qi.pItf;
hr = spRemote->SetUserConfig(TAPI_SERVICE_NAME, strGroup);
Trace1("CServerPropSetup::UpdateSvcHostInfo - SetUserConfig returned %lx\n", hr);
}
CoUninitialize();
return hr;
}
DWORD CServerPropSetup::RestartService()
{
// restart the service if requested
CServerProperties * pServerProp = (CServerProperties * ) GetHolder();
DWORD dwErr = ERROR_SUCCESS;
BOOL fRestart = FALSE;
SPITapiInfo spTapiInfo;
pServerProp->GetTapiInfo(&spTapiInfo);
// gotta clean up before the service stops
spTapiInfo->Destroy();
// any time we stop/start the service we need to call this
::UnloadTapiDll();
// stop the service if it is running
BOOL fServiceRunning = pServerProp->FIsServiceRunning();
::TFSIsServiceRunning(pServerProp->m_strMachineName,
TAPI_SERVICE_NAME,
&fServiceRunning);
if (fServiceRunning)
{
dwErr = ::TFSStopService(pServerProp->m_strMachineName, TAPI_SERVICE_NAME, pServerProp->GetServiceDisplayName());
}
if (dwErr != ERROR_SUCCESS)
{
CString strText;
strText.LoadString(IDS_ERR_SERVICE_NOT_STOPPED);
TapiMessageBox(dwErr, MB_OK, strText);
}
// start the service
if (dwErr == ERROR_SUCCESS)
{
dwErr = ::TFSStartService(pServerProp->m_strMachineName, TAPI_SERVICE_NAME, pServerProp->GetServiceDisplayName());
if (dwErr != ERROR_SUCCESS)
{
CString strText;
strText.LoadString(IDS_ERR_SERVICE_NOT_STARTED);
TapiMessageBox(dwErr, MB_OK, strText);
}
}
StartRefresh();
return dwErr;
}
void CServerPropSetup::StartRefresh()
{
// refresh the snapin to reflect the changes
SPITFSNode spNode;
CTapiServer * pServer;
spNode = GetHolder()->GetNode();
pServer = GETHANDLER(CTapiServer, spNode);
pServer->OnRefresh(spNode, NULL, 0, 0, 0);
}