|
|
/*++
Copyright (c) 1994-95 Microsoft Corporation
Module Name:
srvobj.cpp
Abstract:
Server object implementation.
Author:
Don Ryan (donryan) 04-Jan-1995
Environment:
User Mode - Win32
Revision History:
Jeff Parham (jeffparh) 30-Jan-1996 o Modified to use LlsProductLicensesGet() to avoid race conditions in getting the correct number of concurrent licenses with secure products. o Ported to LlsLocalService API to remove dependencies on configuration information being in the registry.
--*/
#include "stdafx.h"
#include "llsmgr.h"
#include <lm.h>
#include <lmwksta.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__; #endif
IMPLEMENT_DYNCREATE(CServer, CCmdTarget)
BEGIN_MESSAGE_MAP(CServer, CCmdTarget) //{{AFX_MSG_MAP(CServer)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CServer, CCmdTarget) //{{AFX_DISPATCH_MAP(CServer)
DISP_PROPERTY_EX(CServer, "Application", GetApplication, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX(CServer, "Name", GetName, SetNotSupported, VT_BSTR) DISP_PROPERTY_EX(CServer, "Parent", GetParent, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX(CServer, "Controller", GetController, SetNotSupported, VT_BSTR) DISP_PROPERTY_EX(CServer, "IsLogging", IsLogging, SetNotSupported, VT_BOOL) DISP_PROPERTY_EX(CServer, "IsReplicatingToDC", IsReplicatingToDC, SetNotSupported, VT_BOOL) DISP_PROPERTY_EX(CServer, "IsReplicatingDaily", IsReplicatingDaily, SetNotSupported, VT_BOOL) DISP_PROPERTY_EX(CServer, "ReplicationTime", GetReplicationTime, SetNotSupported, VT_I4) DISP_PROPERTY_PARAM(CServer, "Services", GetServices, SetNotSupported, VT_DISPATCH, VTS_VARIANT) DISP_DEFVALUE(CServer, "Name") //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
CServer::CServer(CCmdTarget* pParent, LPCTSTR pName)
/*++
Routine Description:
Constructor for server object.
Arguments:
pParent - creator of object. pName - name of server.
Return Values:
None.
--*/
{ EnableAutomation();
#ifdef ENABLE_PARENT_CHECK
ASSERT(pParent && pParent->IsKindOf(RUNTIME_CLASS(CDomain))); #endif // ENABLE_PARENT_CHECK
m_pParent = pParent;
ASSERT(pName && *pName);
m_strName = pName; m_strController.Empty();
m_pServices = NULL; m_serviceArray.RemoveAll(); m_bServicesRefreshed = FALSE;
m_hkeyRoot = (HKEY)0L; m_hkeyLicense = (HKEY)0L; m_hkeyReplication = (HKEY)0L; m_IsWin2000 = uninitialized;
m_hLls = NULL; }
CServer::~CServer()
/*++
Routine Description:
Destructor for server object.
Arguments:
None.
Return Values:
None.
--*/
{ if (m_pServices) m_pServices->InternalRelease();
#ifdef CONFIG_THROUGH_REGISTRY
if (m_hkeyReplication) RegCloseKey(m_hkeyReplication);
if (m_hkeyLicense) RegCloseKey(m_hkeyLicense);
if (m_hkeyRoot) RegCloseKey(m_hkeyRoot); #endif
DisconnectLls(); }
void CServer::OnFinalRelease()
/*++
Routine Description:
When the last reference for an automation object is released OnFinalRelease is called. This implementation deletes object.
Arguments:
None.
Return Values:
None.
--*/
{ ResetServices(); delete this; }
LPDISPATCH CServer::GetApplication()
/*++
Routine Description:
Returns the application object.
Arguments:
None.
Return Values:
VT_DISPATCH.
--*/
{ return theApp.GetAppIDispatch(); }
BSTR CServer::GetController()
/*++
Routine Description:
Returns license controller for server.
Arguments:
None.
Return Values:
VT_BSTR.
--*/
{ LONG Status; CString strValue = _T("");
if (InitializeIfNecessary()) { #ifdef CONFIG_THROUGH_REGISTRY
TCHAR szValue[256];
DWORD dwType = REG_SZ; DWORD dwSize = sizeof(szValue);
Status = RegQueryValueEx( m_hkeyReplication, REG_VALUE_ENTERPRISE_SERVER, 0, &dwType, (LPBYTE)szValue, &dwSize );
LlsSetLastStatus(Status); // called api
if (Status == ERROR_SUCCESS) strValue = szValue; #else
PLLS_SERVICE_INFO_0 pConfig = NULL;
Status = ::LlsServiceInfoGet( m_hLls, 0, (LPBYTE *) &pConfig );
if ( NT_SUCCESS( Status ) ) { strValue = pConfig->EnterpriseServer;
::LlsFreeMemory( pConfig->ReplicateTo ); ::LlsFreeMemory( pConfig->EnterpriseServer ); ::LlsFreeMemory( pConfig ); } else if ( IsConnectionDropped( Status ) ) { DisconnectLls(); } #endif
}
return strValue.AllocSysString(); }
BSTR CServer::GetName()
/*++
Routine Description:
Returns the name of the server.
Arguments:
None.
Return Values:
VT_BSTR.
--*/
{ return m_strName.AllocSysString(); }
LPDISPATCH CServer::GetParent()
/*++
Routine Description:
Returns the parent of the object.
Arguments:
None.
Return Values:
VT_DISPATCH.
--*/
{ return m_pParent ? m_pParent->GetIDispatch(TRUE) : NULL; }
LPDISPATCH CServer::GetServices(const VARIANT FAR& index)
/*++
Routine Description:
Returns a collection object containing all of the services registered in the server's registry or returns an individual service described by an index into the collection.
Arguments:
index - optional argument that may be a string (VT_BSTR) indicating a service name or a number (VT_I4) indicating the position within collection.
Return Values:
VT_DISPATCH or VT_EMPTY.
--*/
{ LPDISPATCH lpdispatch = NULL;
if (!m_pServices) { m_pServices = new CServices(this, &m_serviceArray); }
if (m_pServices) { if (V_ISVOID((VARIANT FAR*)&index)) { if (RefreshServices()) { lpdispatch = m_pServices->GetIDispatch(TRUE); } } else { if (m_bServicesRefreshed) { lpdispatch = m_pServices->GetItem(index); } else if (RefreshServices()) { lpdispatch = m_pServices->GetItem(index); } } } else { LlsSetLastStatus(STATUS_NO_MEMORY); }
return lpdispatch; }
BOOL CServer::IsLogging()
/*++
Routine Description:
Returns true if server replicating license information.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ return TRUE; // CODEWORK...
}
BOOL CServer::RefreshServices()
/*++
Routine Description:
Refreshs service object list.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ ResetServices();
LONG Status;
if (InitializeIfNecessary()) { #ifdef CONFIG_THROUGH_REGISTRY
TCHAR szValue[260]; DWORD cchValue = sizeof(szValue)/sizeof(TCHAR);
DWORD dwValue; DWORD dwValueType; DWORD dwValueSize;
FILETIME ftLastWritten;
DWORD index = 0L; int iService = 0; HKEY hkeyService = NULL;
CString strServiceName; CString strServiceDisplayName;
BOOL bIsPerServer; BOOL bIsReadOnly;
long lPerServerLimit;
while ((Status = RegEnumKeyEx( m_hkeyLicense, index, szValue, &cchValue, NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
&ftLastWritten )) == ERROR_SUCCESS) { strServiceName = szValue; // store for ctor...
Status = RegOpenKeyEx( m_hkeyLicense, MKSTR(strServiceName), 0, // dwReserved
KEY_ALL_ACCESS, &hkeyService );
if (Status != ERROR_SUCCESS) break; // abort...
dwValueType = REG_SZ; dwValueSize = sizeof(szValue);
Status = RegQueryValueEx( hkeyService, REG_VALUE_NAME, 0, // dwReserved
&dwValueType, (LPBYTE)&szValue[0], &dwValueSize );
if (Status != ERROR_SUCCESS) break; // abort...
strServiceDisplayName = szValue;
dwValueType = REG_DWORD; dwValueSize = sizeof(DWORD);
Status = RegQueryValueEx( hkeyService, REG_VALUE_MODE, 0, // dwReserved
&dwValueType, (LPBYTE)&dwValue, &dwValueSize );
if (Status != ERROR_SUCCESS) break; // abort...
//
// 0x0 = per seat mode
// 0x1 = per server mode
//
bIsPerServer = (dwValue == 0x1);
dwValueType = REG_DWORD; dwValueSize = sizeof(DWORD);
Status = RegQueryValueEx( hkeyService, REG_VALUE_FLIP, 0, // dwReserved
&dwValueType, (LPBYTE)&dwValue, &dwValueSize );
if (Status != ERROR_SUCCESS) break; // abort...
//
// 0x0 = can change mode
// 0x1 = can't change mode
//
bIsReadOnly = (dwValue == 0x1);
BOOL bGetLimitFromRegistry = TRUE;
if ( ConnectLls() ) { Status = LlsProductLicensesGet( m_hLls, MKSTR(strServiceDisplayName), LLS_LICENSE_MODE_PER_SERVER, &dwValue );
if ( STATUS_SUCCESS == Status ) { bGetLimitFromRegistry = FALSE; } }
if ( bGetLimitFromRegistry ) { dwValueType = REG_DWORD; dwValueSize = sizeof(DWORD);
Status = RegQueryValueEx( hkeyService, REG_VALUE_LIMIT, 0, // dwReserved
&dwValueType, (LPBYTE)&dwValue, &dwValueSize ); }
if (Status != ERROR_SUCCESS) break; // abort...
lPerServerLimit = (long)dwValue;
CService* pService = new CService(this, strServiceName, strServiceDisplayName, bIsPerServer, bIsReadOnly, lPerServerLimit );
m_serviceArray.SetAtGrow(iService++, pService); index++;
cchValue = sizeof(szValue)/sizeof(TCHAR);
RegCloseKey(hkeyService); // no longer needed...
hkeyService = NULL; }
if (hkeyService) RegCloseKey(hkeyService);
if (Status == ERROR_NO_MORE_ITEMS) Status = ERROR_SUCCESS;
LlsSetLastStatus(Status); // called api
if (Status == ERROR_SUCCESS) { m_bServicesRefreshed = TRUE; } else { ResetServices(); } #else
DWORD dwResumeHandle = 0; int iService = 0;
do { PLLS_LOCAL_SERVICE_INFO_0 pServiceList = NULL; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0;
Status = ::LlsLocalServiceEnum( m_hLls, 0, (LPBYTE *) &pServiceList, LLS_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle );
if ( NT_SUCCESS( Status ) ) { DWORD i;
for ( i=0; i < dwEntriesRead; i++ ) { BOOL bIsPerServer = ( LLS_LICENSE_MODE_PER_SERVER == pServiceList[ i ].Mode ); BOOL bIsReadOnly = ( 0 == pServiceList[ i ].FlipAllow ); DWORD dwConcurrentLimit;
// get number of per server license in case where product
// is secure, and
// ( is currently in per seat mode, or
// new secure per server licenses have just been added and registry
// has not been updated yet )
if ( STATUS_SUCCESS != LlsProductLicensesGet( m_hLls, pServiceList[ i ].DisplayName, LLS_LICENSE_MODE_PER_SERVER, &dwConcurrentLimit ) ) { dwConcurrentLimit = pServiceList[ i ].ConcurrentLimit; }
CService* pService = new CService( this, pServiceList[ i ].KeyName, pServiceList[ i ].DisplayName, bIsPerServer, bIsReadOnly, dwConcurrentLimit );
m_serviceArray.SetAtGrow(iService++, pService);
::LlsFreeMemory( pServiceList[ i ].KeyName ); ::LlsFreeMemory( pServiceList[ i ].DisplayName ); ::LlsFreeMemory( pServiceList[ i ].FamilyDisplayName ); }
::LlsFreeMemory( pServiceList ); } } while ( STATUS_MORE_ENTRIES == Status );
LlsSetLastStatus( Status ); // called api
if ( NT_SUCCESS( Status ) ) { m_bServicesRefreshed = TRUE; } else { ResetServices();
if ( IsConnectionDropped( Status ) ) { DisconnectLls(); } } #endif
}
return m_bServicesRefreshed; }
void CServer::ResetServices()
/*++
Routine Description:
Resets service object list.
Arguments:
None.
Return Values:
None.
--*/
{ CService* pService; INT_PTR iService = m_serviceArray.GetSize();
while (iService--) { pService = (CService*)m_serviceArray[iService]; if (NULL != pService) { ASSERT(pService->IsKindOf(RUNTIME_CLASS(CService))); pService->InternalRelease(); } }
m_serviceArray.RemoveAll(); m_bServicesRefreshed = FALSE; }
BOOL CServer::InitializeIfNecessary()
/*++
Routine Description:
Initialize registry keys if necessary.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ #ifdef CONFIG_THROUGH_REGISTRY
LONG Status = ERROR_SUCCESS;
if (!m_hkeyRoot) { Status = RegConnectRegistry( MKSTR(m_strName), HKEY_LOCAL_MACHINE, &m_hkeyRoot );
LlsSetLastStatus(Status); // called api
}
if (!m_hkeyLicense && (Status == ERROR_SUCCESS)) { ASSERT(m_hkeyRoot);
Status = RegOpenKeyEx( m_hkeyRoot, REG_KEY_LICENSE, 0, // dwReserved
KEY_ALL_ACCESS, &m_hkeyLicense );
LlsSetLastStatus(Status); // called api
}
if (!m_hkeyReplication && (Status == ERROR_SUCCESS)) { ASSERT(m_hkeyRoot);
Status = RegOpenKeyEx( m_hkeyRoot, REG_KEY_SERVER_PARAMETERS, 0, // dwReserved
KEY_ALL_ACCESS, &m_hkeyReplication );
LlsSetLastStatus(Status); // called api
}
return (Status == ERROR_SUCCESS); #else
return ConnectLls(); #endif
}
BOOL CServer::IsReplicatingToDC()
/*++
Routine Description:
Returns true if server replicating to domain controller.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ LONG Status; DWORD dwValue = 0;
if (InitializeIfNecessary()) { #ifdef CONFIG_THROUGH_REGISTRY
DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD);
Status = RegQueryValueEx( m_hkeyReplication, REG_VALUE_USE_ENTERPRISE, 0, &dwType, (LPBYTE)&dwValue, &dwSize ); #else
PLLS_SERVICE_INFO_0 pConfig = NULL;
Status = ::LlsServiceInfoGet( m_hLls, 0, (LPBYTE *) &pConfig );
if ( NT_SUCCESS( Status ) ) { dwValue = pConfig->UseEnterprise;
::LlsFreeMemory( pConfig->ReplicateTo ); ::LlsFreeMemory( pConfig->EnterpriseServer ); ::LlsFreeMemory( pConfig ); }
if ( IsConnectionDropped( Status ) ) { DisconnectLls(); } #endif
LlsSetLastStatus(Status); // called api
}
return !((BOOL)dwValue); }
BOOL CServer::IsReplicatingDaily()
/*++
Routine Description:
Returns true if server replicating daily at certain time.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ LONG Status; DWORD dwValue = 0;
if (InitializeIfNecessary()) { #ifdef CONFIG_THROUGH_REGISTRY
DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD);
Status = RegQueryValueEx( m_hkeyReplication, REG_VALUE_REPLICATION_TYPE, 0, &dwType, (LPBYTE)&dwValue, &dwSize ); #else
PLLS_SERVICE_INFO_0 pConfig = NULL;
Status = ::LlsServiceInfoGet( m_hLls, 0, (LPBYTE *) &pConfig );
if ( NT_SUCCESS( Status ) ) { dwValue = pConfig->ReplicationType;
::LlsFreeMemory( pConfig->ReplicateTo ); ::LlsFreeMemory( pConfig->EnterpriseServer ); ::LlsFreeMemory( pConfig ); }
if ( IsConnectionDropped( Status ) ) { DisconnectLls(); } #endif
LlsSetLastStatus(Status); // called api
}
return (dwValue == LLS_REPLICATION_TYPE_TIME); }
long CServer::GetReplicationTime()
/*++
Routine Description:
Returns time in seconds between replication or seconds from midnight if replicating daily.
Arguments:
None.
Return Values:
VT_I4.
--*/
{ LONG Status; DWORD dwValue = 0;
if (InitializeIfNecessary()) { #ifdef CONFIG_THROUGH_REGISTRY
DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD);
Status = RegQueryValueEx( m_hkeyReplication, REG_VALUE_REPLICATION_TIME, 0, &dwType, (LPBYTE)&dwValue, &dwSize ); #else
PLLS_SERVICE_INFO_0 pConfig = NULL;
Status = ::LlsServiceInfoGet( m_hLls, 0, (LPBYTE *) &pConfig );
if ( NT_SUCCESS( Status ) ) { dwValue = pConfig->ReplicationTime;
::LlsFreeMemory( pConfig->ReplicateTo ); ::LlsFreeMemory( pConfig->EnterpriseServer ); ::LlsFreeMemory( pConfig ); }
if ( IsConnectionDropped( Status ) ) { DisconnectLls(); } #endif
LlsSetLastStatus(Status); // called api
}
return dwValue; }
BOOL CServer::ConnectLls()
/*++
Routine Description:
Connects to license service on this server.
Arguments:
None.
Return Values:
VT_BOOL.
--*/
{ NTSTATUS Status;
if ( NULL == m_hLls ) { CString strNetServerName = m_strName;
if ( strNetServerName.Left(2).Compare( TEXT( "\\\\" ) ) ) { strNetServerName = TEXT( "\\\\" ) + strNetServerName; }
Status = LlsConnect( MKSTR(strNetServerName), &m_hLls );
if ( STATUS_SUCCESS != Status ) { m_hLls = NULL; } else if ( !HaveAdminAuthority() ) { m_hLls = NULL; Status = ERROR_ACCESS_DENIED; }
LlsSetLastStatus( Status ); }
return ( NULL != m_hLls ); }
void CServer::DisconnectLls()
/*++
Routine Description:
Disconnects from license service on this server.
Arguments:
None.
Return Values:
None.
--*/
{ if ( NULL != m_hLls ) { LlsClose( m_hLls );
m_hLls = NULL; } }
BOOL CServer::HaveAdminAuthority()
/*++
Routine Description:
Checks whether the current user has admin authority on the server.
Arguments:
None.
Return Values:
BOOL.
--*/
{ BOOL bIsAdmin; CString strNetShareName;
strNetShareName = m_strName + TEXT( "\\ADMIN$" );
if ( strNetShareName.Left(2).Compare( TEXT( "\\\\" ) ) ) { strNetShareName = TEXT( "\\\\" ) + strNetShareName; }
#ifdef USE_WNET_API
DWORD dwError; NETRESOURCE NetResource;
ZeroMemory( &NetResource, sizeof( NetResource ) );
NetResource.dwType = RESOURCETYPE_DISK; NetResource.lpLocalName = NULL; NetResource.lpRemoteName = MKSTR(strNetShareName); NetResource.lpProvider = NULL;
dwError = WNetAddConnection2( &NetResource, NULL, NULL, 0 );
bIsAdmin = ( NO_ERROR == dwError );
if ( NO_ERROR != dwError ) { bIsAdmin = FALSE; } else { bIsAdmin = TRUE;
WNetCancelConnection2( MKSTR(strNetShareName), 0, FALSE ); } #else
NET_API_STATUS NetStatus; USE_INFO_1 UseInfo; DWORD dwErrorParm;
ZeroMemory( &UseInfo, sizeof( UseInfo ) );
UseInfo.ui1_remote = MKSTR( strNetShareName );
NetStatus = NetUseAdd( NULL, 1, (LPBYTE) &UseInfo, &dwErrorParm );
if ( NERR_Success != NetStatus ) { bIsAdmin = FALSE; } else { bIsAdmin = TRUE;
NetStatus = NetUseDel( NULL, MKSTR(strNetShareName), 0 ); // ignore status
} #endif
return bIsAdmin; }
BOOL CServer::IsWin2000()
/*++
Routine Description:
Checks whether the current server is Windows 2000 or greater.
Arguments:
None.
Return Values:
BOOL.
--*/
{ if ( m_IsWin2000 == uninitialized ) { if ( GetName() != NULL ) { NET_API_STATUS NetStatus; PWKSTA_INFO_100 pWkstaInfo100 = NULL;
NetStatus = NetWkstaGetInfo( GetName(), 100, (LPBYTE*)&pWkstaInfo100 );
if (NetStatus == ERROR_SUCCESS) { if (pWkstaInfo100->wki100_ver_major < 5) { m_IsWin2000 = notwin2000; } else { m_IsWin2000 = win2000; }
NetApiBufferFree(pWkstaInfo100); } } }
// if still unitialized, assume win2000.
return ( !(m_IsWin2000 == notwin2000) ); }
|