Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1631 lines
39 KiB

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/
/*
spddb.h
FILE HISTORY:
*/
#include "stdafx.h"
#include "DynamLnk.h"
#include "spddb.h"
#include "spdutil.h"
#include "security.h"
#include "lm.h"
#include "service.h"
#define AVG_PREFERRED_ENUM_COUNT 40
#define MAX_NUM_RECORDS 10 // was 10
#define DEFAULT_SECURITY_PKG _T("negotiate")
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
//
// The database holds 5K records and wraps around. So we dont cache more than
// 5K records.
//
#define WZCDB_DEFAULT_NUM_RECS 5000
// internal functions
BOOL IsUserAdmin(LPCTSTR pszMachine, PSID AccountSid);
BOOL LookupAliasFromRid(LPWSTR TargetComputer, DWORD Rid, LPWSTR Name, PDWORD cchName);
DWORD ValidateDomainAccount(IN CString Machine, IN CString UserName, IN CString Domain, OUT PSID * AccountSid);
NTSTATUS ValidatePassword(IN LPCWSTR UserName, IN LPCWSTR Domain, IN LPCWSTR Password);
DWORD GetCurrentUser(CString & strAccount);
DWORD GetCurrentUser(CString & strAccount)
{
LPBYTE pBuf;
NET_API_STATUS status = NetWkstaUserGetInfo(NULL, 1, &pBuf);
if (status == NERR_Success)
{
strAccount.Empty();
WKSTA_USER_INFO_1 * pwkstaUserInfo = (WKSTA_USER_INFO_1 *) pBuf;
strAccount = pwkstaUserInfo->wkui1_logon_domain;
strAccount += _T("\\");
strAccount += pwkstaUserInfo->wkui1_username;
NetApiBufferFree(pBuf);
}
return (DWORD) status;
}
/*!--------------------------------------------------------------------------
IsAdmin
Connect to the remote machine as administrator with user-supplied
credentials to see if the user has admin priviledges
Returns
TRUE - the user has admin rights
FALSE - if user doesn't
Author: EricDav, KennT
---------------------------------------------------------------------------*/
DWORD IsAdmin(LPCTSTR szMachineName, LPCTSTR szAccount, LPCTSTR szPassword, BOOL * pIsAdmin)
{
CString stAccount;
CString stDomain;
CString stUser;
CString stMachineName;
DWORD dwStatus;
BOOL fIsAdmin = FALSE;
// get the current user info
if (szAccount == NULL)
{
GetCurrentUser(stAccount);
}
else
{
stAccount = szAccount;
}
// separate the user and domain
int nPos = stAccount.Find(_T("\\"));
stDomain = stAccount.Left(nPos);
stUser = stAccount.Right(stAccount.GetLength() - nPos - 1);
// build the machine string
stMachineName = szMachineName;
if ( stMachineName.Left(2) != TEXT( "\\\\" ) )
{
stMachineName = TEXT( "\\\\" ) + stMachineName;
}
// validate the domain account and get the sid
PSID connectSid;
dwStatus = ValidateDomainAccount( stMachineName, stUser, stDomain, &connectSid );
if ( dwStatus != ERROR_SUCCESS )
{
goto Error;
}
// if a password was supplied, is it correct?
if (szPassword)
{
dwStatus = ValidatePassword( stUser, stDomain, szPassword );
if ( dwStatus != SEC_E_OK )
{
switch ( dwStatus )
{
case SEC_E_LOGON_DENIED:
dwStatus = ERROR_INVALID_PASSWORD;
break;
case SEC_E_INVALID_HANDLE:
dwStatus = ERROR_INTERNAL_ERROR;
break;
default:
dwStatus = ERROR_INTERNAL_ERROR;
break;
} // end of switch
goto Error;
} // Did ValidatePassword succeed?
}
// now check the machine to see if this account has admin access
fIsAdmin = IsUserAdmin( stMachineName, connectSid );
Error:
if (pIsAdmin)
*pIsAdmin = fIsAdmin;
return dwStatus;
}
BOOL
IsUserAdmin(LPCTSTR pszMachine,
PSID AccountSid)
/*++
Routine Description:
Determine if the specified account is a member of the local admin's group
Arguments:
AccountSid - pointer to service account Sid
Return Value:
True if member
--*/
{
NET_API_STATUS status;
DWORD count;
WCHAR adminGroupName[UNLEN+1];
DWORD cchName = UNLEN;
PLOCALGROUP_MEMBERS_INFO_0 grpMemberInfo;
PLOCALGROUP_MEMBERS_INFO_0 pInfo;
DWORD entriesRead;
DWORD totalEntries;
DWORD_PTR resumeHandle = NULL;
DWORD bufferSize = 128;
BOOL foundEntry = FALSE;
// get the name of the admin's group
if (!LookupAliasFromRid(NULL,
DOMAIN_ALIAS_RID_ADMINS,
adminGroupName,
&cchName)) {
return(FALSE);
}
// get the Sids of the members of the admin's group
do
{
status = NetLocalGroupGetMembers(pszMachine,
adminGroupName,
0, // level 0 - just the Sid
(LPBYTE *)&grpMemberInfo,
bufferSize,
&entriesRead,
&totalEntries,
&resumeHandle);
bufferSize *= 2;
if ( status == ERROR_MORE_DATA )
{
// we got some of the data but I want it all; free this buffer and
// reset the context handle for the API
NetApiBufferFree( grpMemberInfo );
resumeHandle = NULL;
}
} while ( status == NERR_BufTooSmall || status == ERROR_MORE_DATA );
if ( status == NERR_Success )
{
// loop through the members of the admin group, comparing the supplied
// Sid to that of the group members' Sids
for ( count = 0, pInfo = grpMemberInfo; count < totalEntries; ++count, ++pInfo )
{
if ( EqualSid( AccountSid, pInfo->lgrmi0_sid ))
{
foundEntry = TRUE;
break;
}
}
NetApiBufferFree( grpMemberInfo );
}
return foundEntry;
}
//
//
//
BOOL
LookupAliasFromRid(
LPWSTR TargetComputer,
DWORD Rid,
LPWSTR Name,
PDWORD cchName
)
{
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
SID_NAME_USE snu;
PSID pSid;
WCHAR DomainName[DNLEN+1];
DWORD cchDomainName = DNLEN;
BOOL bSuccess = FALSE;
//
// Sid is the same regardless of machine, since the well-known
// BUILTIN domain is referenced.
//
if(AllocateAndInitializeSid(&sia,
2,
SECURITY_BUILTIN_DOMAIN_RID,
Rid,
0, 0, 0, 0, 0, 0,
&pSid)) {
bSuccess = LookupAccountSidW(TargetComputer,
pSid,
Name,
cchName,
DomainName,
&cchDomainName,
&snu);
FreeSid(pSid);
}
return bSuccess;
} // LookupAliasFromRid
DWORD
ValidateDomainAccount(
IN CString Machine,
IN CString UserName,
IN CString Domain,
OUT PSID * AccountSid
)
/*++
Routine Description:
For the given credentials, look up the account SID for the specified
domain. As a side effect, the Sid is stored in theData->m_Sid.
Arguments:
pointers to strings that describe the user name, domain name, and password
AccountSid - address of pointer that receives the SID for this user
Return Value:
TRUE if everything validated ok.
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwSidSize = 128;
DWORD dwDomainNameSize = 128;
LPWSTR pwszDomainName;
SID_NAME_USE SidType;
CString domainAccount;
PSID accountSid;
domainAccount = Domain + _T("\\") + UserName;
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 );
}
if ( pwszDomainName != NULL ) {
LocalFree( pwszDomainName );
}
//FATALERR( IDS_ERR_NOT_ENOUGH_MEMORY, GetLastError() ); // no return
break;
}
// 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( Machine,
domainAccount,
accountSid,
&dwSidSize,
pwszDomainName,
&dwDomainNameSize,
&SidType ))
{
// free the Sid buffer and find out why we failed
LocalFree( accountSid );
dwStatus = GetLastError();
}
// domain name isn't needed at any time
LocalFree( pwszDomainName );
pwszDomainName = NULL;
} while ( dwStatus == ERROR_INSUFFICIENT_BUFFER );
if ( dwStatus == ERROR_SUCCESS ) {
*AccountSid = accountSid;
}
return dwStatus;
} // ValidateDomainAccount
NTSTATUS
ValidatePassword(
IN LPCWSTR UserName,
IN LPCWSTR Domain,
IN LPCWSTR Password
)
/*++
Routine Description:
Uses SSPI to validate the specified password
Arguments:
UserName - Supplies the user name
Domain - Supplies the user's domain
Password - Supplies the password
Return Value:
TRUE if the password is valid.
FALSE otherwise.
--*/
{
SECURITY_STATUS SecStatus;
SECURITY_STATUS AcceptStatus;
SECURITY_STATUS InitStatus;
CredHandle ClientCredHandle;
CredHandle ServerCredHandle;
BOOL ClientCredAllocated = FALSE;
BOOL ServerCredAllocated = FALSE;
CtxtHandle ClientContextHandle;
CtxtHandle ServerContextHandle;
TimeStamp Lifetime;
ULONG ContextAttributes;
PSecPkgInfo PackageInfo = NULL;
ULONG ClientFlags;
ULONG ServerFlags;
SEC_WINNT_AUTH_IDENTITY_W AuthIdentity;
SecBufferDesc NegotiateDesc;
SecBuffer NegotiateBuffer;
SecBufferDesc ChallengeDesc;
SecBuffer ChallengeBuffer;
SecBufferDesc AuthenticateDesc;
SecBuffer AuthenticateBuffer;
SecBufferDesc *pChallengeDesc = NULL;
CtxtHandle * pClientContextHandle = NULL;
CtxtHandle * pServerContextHandle = NULL;
AuthIdentity.User = (LPWSTR)UserName;
AuthIdentity.UserLength = lstrlenW(UserName);
AuthIdentity.Domain = (LPWSTR)Domain;
AuthIdentity.DomainLength = lstrlenW(Domain);
AuthIdentity.Password = (LPWSTR)Password;
AuthIdentity.PasswordLength = lstrlenW(Password);
AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
NegotiateBuffer.pvBuffer = NULL;
ChallengeBuffer.pvBuffer = NULL;
AuthenticateBuffer.pvBuffer = NULL;
//
// Get info about the security packages.
//
SecStatus = QuerySecurityPackageInfo( DEFAULT_SECURITY_PKG, &PackageInfo );
if ( SecStatus != STATUS_SUCCESS ) {
goto error_exit;
}
//
// Acquire a credential handle for the server side
//
SecStatus = AcquireCredentialsHandle(
NULL,
DEFAULT_SECURITY_PKG,
SECPKG_CRED_INBOUND,
NULL,
&AuthIdentity,
NULL,
NULL,
&ServerCredHandle,
&Lifetime );
if ( SecStatus != STATUS_SUCCESS ) {
goto error_exit;
}
ServerCredAllocated = TRUE;
//
// Acquire a credential handle for the client side
//
SecStatus = AcquireCredentialsHandle(
NULL, // New principal
DEFAULT_SECURITY_PKG,
SECPKG_CRED_OUTBOUND,
NULL,
&AuthIdentity,
NULL,
NULL,
&ClientCredHandle,
&Lifetime );
if ( SecStatus != STATUS_SUCCESS ) {
goto error_exit;
}
ClientCredAllocated = TRUE;
NegotiateBuffer.pvBuffer = LocalAlloc( 0, PackageInfo->cbMaxToken ); // [CHKCHK] check or allocate this earlier //
if ( NegotiateBuffer.pvBuffer == NULL ) {
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
goto error_exit;
}
ChallengeBuffer.pvBuffer = LocalAlloc( 0, PackageInfo->cbMaxToken ); // [CHKCHK]
if ( ChallengeBuffer.pvBuffer == NULL ) {
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
goto error_exit;
}
do {
//
// Get the NegotiateMessage (ClientSide)
//
NegotiateDesc.ulVersion = 0;
NegotiateDesc.cBuffers = 1;
NegotiateDesc.pBuffers = &NegotiateBuffer;
NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken;
ClientFlags = 0; // ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT; // [CHKCHK] 0
InitStatus = InitializeSecurityContext(
&ClientCredHandle,
pClientContextHandle, // (NULL on the first pass, partially formed ctx on the next)
NULL, // [CHKCHK] szTargetName
ClientFlags,
0, // Reserved 1
SECURITY_NATIVE_DREP,
pChallengeDesc, // (NULL on the first pass)
0, // Reserved 2
&ClientContextHandle,
&NegotiateDesc,
&ContextAttributes,
&Lifetime );
// BUGBUG - the following call to NT_SUCCESS should be replaced with something.
if ( !NT_SUCCESS(InitStatus) ) {
SecStatus = InitStatus;
goto error_exit;
}
// ValidateBuffer( &NegotiateDesc ) // [CHKCHK]
pClientContextHandle = &ClientContextHandle;
//
// Get the ChallengeMessage (ServerSide)
//
NegotiateBuffer.BufferType |= SECBUFFER_READONLY;
ChallengeDesc.ulVersion = 0;
ChallengeDesc.cBuffers = 1;
ChallengeDesc.pBuffers = &ChallengeBuffer;
ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
ServerFlags = ASC_REQ_ALLOW_NON_USER_LOGONS; // ASC_REQ_EXTENDED_ERROR; [CHKCHK]
AcceptStatus = AcceptSecurityContext(
&ServerCredHandle,
pServerContextHandle, // (NULL on the first pass)
&NegotiateDesc,
ServerFlags,
SECURITY_NATIVE_DREP,
&ServerContextHandle,
&ChallengeDesc,
&ContextAttributes,
&Lifetime );
// BUGBUG - the following call to NT_SUCCESS should be replaced with something.
if ( !NT_SUCCESS(AcceptStatus) ) {
SecStatus = AcceptStatus;
goto error_exit;
}
// ValidateBuffer( &NegotiateDesc ) // [CHKCHK]
pChallengeDesc = &ChallengeDesc;
pServerContextHandle = &ServerContextHandle;
} while ( AcceptStatus == SEC_I_CONTINUE_NEEDED ); // || InitStatus == SEC_I_CONTINUE_NEEDED );
error_exit:
if (ServerCredAllocated) {
FreeCredentialsHandle( &ServerCredHandle );
}
if (ClientCredAllocated) {
FreeCredentialsHandle( &ClientCredHandle );
}
//
// Final Cleanup
//
if ( NegotiateBuffer.pvBuffer != NULL ) {
(VOID) LocalFree( NegotiateBuffer.pvBuffer );
}
if ( ChallengeBuffer.pvBuffer != NULL ) {
(VOID) LocalFree( ChallengeBuffer.pvBuffer );
}
if ( AuthenticateBuffer.pvBuffer != NULL ) {
(VOID) LocalFree( AuthenticateBuffer.pvBuffer );
}
return(SecStatus);
} // ValidatePassword
DEBUG_DECLARE_INSTANCE_COUNTER(CSpdInfo);
CSpdInfo::CSpdInfo()
: m_cRef(1),
m_Init(0),
m_Active(0),
m_session_init(false),
m_dwSortIndex(IDS_COL_LOGDATA_TIME),
m_dwSortOption(SORT_ASCENDING),
m_nNumRecords(WZCDB_DEFAULT_NUM_RECS),
m_bEliminateDuplicates(FALSE)
{
HRESULT hr = S_OK;
HANDLE hSession = NULL;
/*
Either we opened a session successfully or we found out that logging
is disabled. If logging is disabled then we check every time EnumLogData
is called to see if we can access the database.
*/
DEBUG_INCREMENT_INSTANCE_COUNTER(CSpdInfo);
}
CSpdInfo::~CSpdInfo()
{
DEBUG_DECREMENT_INSTANCE_COUNTER(CSpdInfo);
CSingleLock cLock(&m_csData);
cLock.Lock();
//Convert the data to our internal data structure
//FreeItemsAndEmptyArray(m_arrayFWFilters);
FreeItemsAndEmptyArray(m_arrayLogData);
cLock.Unlock();
}
// Although this object is not a COM Interface, we want to be able to
// take advantage of recounting, so we have basic addref/release/QI support
IMPLEMENT_ADDREF_RELEASE(CSpdInfo)
IMPLEMENT_SIMPLE_QUERYINTERFACE(CSpdInfo, ISpdInfo)
void
CSpdInfo::FreeItemsAndEmptyArray(
CLogDataInfoArray& array
)
{
for (int i = 0; i < array.GetSize(); i++)
{
delete array.GetAt(i);
}
array.RemoveAll();
}
HRESULT
CSpdInfo::SetComputerName(
LPTSTR pszName
)
{
m_stMachineName = pszName;
return S_OK;
}
HRESULT
CSpdInfo::GetComputerName(
CString * pstName
)
{
Assert(pstName);
if (NULL == pstName)
return E_INVALIDARG;
*pstName = m_stMachineName;
return S_OK;
}
HRESULT
CSpdInfo::GetSession(
PHANDLE phsession
)
{
Assert(session);
if (NULL == phsession)
return E_INVALIDARG;
*phsession = m_session;
return S_OK;
}
HRESULT
CSpdInfo::SetSession(
HANDLE hsession
)
{
m_csData.Lock();
m_session = hsession;
m_session_init = true;
m_bFromFirst = TRUE;
m_csData.Unlock();
return S_OK;
}
HRESULT
CSpdInfo::ResetSession()
/*++
CSpdInfo::ResetSession:
Used to reset the session when the logging is turned off so that we dont
use a bad session.
Arguments:
None
Returns:
Always returns S_OK
--*/
{
if (m_session != NULL)
CloseWZCDbLogSession(m_session);
m_session = NULL;
m_session_init = false;
return S_OK;
}
DWORD
CSpdInfo::EliminateDuplicates(
CLogDataInfoArray *pArray
)
/*++
CSpdInfo::EliminateDuplicates: Removes duplicate records from the given
array.
If the database moves past the end of the table, it cannot move
to get new records on the next refresh cyle, hence it always remains
on the last record. So if our cache size is the same as the database
size, then we must delete the first record as the new enumeration
would have resulted in a duplicate record.
We also know that in only the first element is a duplicate
Arguments:
[in/out] pArray - Pointer to array containing elements. On exit contains
all non duplicate elements
Returns:
ERROR_SUCCESS on success
--*/
{
int i = 0;
int j = 0;
int nSize = 0;
DWORD dwErr = ERROR_SUCCESS;
CLogDataInfo *pLog = NULL;
if (NULL == pArray)
{
dwErr = ERROR_INVALID_PARAMETER;
goto done;
}
nSize = (int) pArray->GetSize();
if (0 == nSize)
goto done;
//Merely delete the first element
pLog = pArray->GetAt(0);
delete pLog;
pArray->RemoveAt(0);
done:
return dwErr;
}
void
CSpdInfo::StartFromFirstRecord(
BOOL bFromFirst)
/*++
Routine Description:
CSpdInfo::StartFromFirstRecord:
Sets the read location to start from the first or from the end of the
table
Arguments:
IN bFromFirst - TRUE if the read should be done from the beginning of the
database, FALSE otherwise
Returns:
Nothing.
--*/
{
m_csData.Lock();
m_bFromFirst = bFromFirst;
m_csData.Unlock();
}
HRESULT
CSpdInfo::InternalEnumLogData(
CLogDataInfoArray *pArray,
DWORD dwPreferredNum,
BOOL bFromFirst
)
/*++
Routine Description:
CSpdInfo::InternalEnumLogData - Enumerates data from the service and adds
to pArray.
Arguments:
[out] pArray - New values are appended if any
[in] dwPreferredNum - Holds the number of records requested
Returns:
HRESULT_FROM_WIN32() of the following codes
ERROR_SUCCESS on success
ERROR_NO_MORE_ITEMS on no more items
ERROR_SERVICE_DISABLED otherwise
--*/
{
HRESULT hr = hrOK;
DWORD dwErr = ERROR_SUCCESS;
HANDLE hsession = NULL;
DWORD dwCrtNum = 0;
PWZC_DB_RECORD pDbRecord = NULL;
PWZC_DB_RECORD pWZCRecords = NULL;
DWORD dwNumRecords = 0;
CLogDataInfo *pLogDataInfo = NULL;
int i = 0;
ASSERT(pArray);
FreeItemsAndEmptyArray(*pArray);
GetSession(&hsession);
while (ERROR_SUCCESS == dwErr)
{
dwCrtNum = (DWORD)pArray->GetSize();
dwErr = EnumWZCDbLogRecords(hsession,
NULL,
&bFromFirst,
dwPreferredNum,
&pWZCRecords,
&dwNumRecords,
NULL);
bFromFirst = FALSE;
pArray->SetSize(dwCrtNum + dwNumRecords);
for (i = 0, pDbRecord = pWZCRecords;
i < (int)dwNumRecords;
i++, pDbRecord++)
{
pLogDataInfo = new CLogDataInfo;
if (NULL == pLogDataInfo)
{
hr = E_OUTOFMEMORY;
goto Error;
}
*pLogDataInfo = *pDbRecord;
(*pArray)[dwCrtNum + i] = pLogDataInfo;
RpcFree(pDbRecord->message.pData);
RpcFree(pDbRecord->context.pData);
RpcFree(pDbRecord->ssid.pData);
RpcFree(pDbRecord->remotemac.pData);
RpcFree(pDbRecord->localmac.pData);
}
RpcFree(pWZCRecords);
}
switch (dwErr)
{
case ERROR_SUCCESS:
case ERROR_NO_MORE_ITEMS:
hr = HRESULT_FROM_WIN32(ERROR_SUCCESS);
break;
default:
hr = HRESULT_FROM_WIN32(dwErr);
break;
}
COM_PROTECT_ERROR_LABEL;
return hr;
}
HRESULT
CSpdInfo::EnumLogData(
PDWORD pdwNew,
PDWORD pdwTotal)
/*++
Routine Description:
CSpdInfo::EnumLogData:
Enumerates logs differentially
Arguments:
Returns:
--*/
{
int i = 0;
int nStoreSize = 0;
int nTempStoreSize = 0;
int nNumToDel = 0;
HRESULT hr = hrOK;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwCurrentIndexType = 0;
DWORD dwCurrentSortOption = 0;
DWORD dwNumRequest = MAX_NUM_RECORDS;
DWORD dwOffset = 0;
DWORD dwStoreSize = 0;
HANDLE hSession = NULL;
CLogDataInfo *pLogInfo = NULL;
CLogDataInfoArray arrayTemp;
BOOL bFromFirst = FALSE;
if (false == m_session_init)
{
dwErr = OpenWZCDbLogSession(
NULL/*(LPTSTR)(LPCTSTR)m_stMachineName*/,
0,
&hSession);
if (dwErr != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwErr);
goto Error;
}
SetSession(hSession);
}
ASSERT(m_session_init == true);
//
// If our session was created successfully, we should go ahead and pick up
// data from the database. If not we should return.
//
dwStoreSize = GetLogDataCount();
if (dwStoreSize == 0)
bFromFirst = TRUE;
CORg(InternalEnumLogData(&arrayTemp, dwNumRequest, bFromFirst));
m_csData.Lock();
nTempStoreSize = (int) arrayTemp.GetSize();
if (pdwNew != NULL)
*pdwNew = nTempStoreSize;
//
// Add new items to our cache. If we have read records our earlier, remove
// the first element from the new array, as the database would return the
// last record once again.
//
if (nTempStoreSize > 0)
{
if (bFromFirst == FALSE)
EliminateDuplicates(&arrayTemp);
m_arrayLogData.Append(arrayTemp);
}
//
// Delete the old items if we are at the window
//
nStoreSize = (int) m_arrayLogData.GetSize();
if (nStoreSize >= m_nNumRecords)
{
nNumToDel = nStoreSize - m_nNumRecords;
//
// The oldest elements are at zero
//
for (i=0; i < nNumToDel; i++)
delete m_arrayLogData.GetAt(i);
m_arrayLogData.RemoveAt(0, nNumToDel);
ASSERT(m_nNumRecords == m_arrayLogData.GetSize());
nStoreSize = m_nNumRecords;
}
if (pdwTotal != NULL)
*pdwTotal = nStoreSize;
m_IndexMgrLogData.Reset();
for (i = 0; i < nStoreSize; i++)
{
pLogInfo = m_arrayLogData.GetAt(i);
m_IndexMgrLogData.AddItem(pLogInfo);
}
//
// Re-sort based on the IndexType and Sort options
//
SortLogData(m_dwSortIndex, m_dwSortOption);
m_csData.Unlock();
COM_PROTECT_ERROR_LABEL;
if (FAILED(hr))
{
switch (hr)
{
case HRESULT_FROM_WIN32(ERROR_REMOTE_SESSION_LIMIT_EXCEEDED):
//
// Pop up a message...
//
AfxMessageBox(
IDS_ERR_SPD_UNAVAILABLE,
MB_OK | MB_ICONEXCLAMATION,
0);
case HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED):
//
// Reset the session if initialised
//
if (m_session_init == true)
ResetSession();
//
// Flush the logs
//
FlushLogs();
hr = S_OK;
break;
default:
//
// Unexpected error, this should never happen.
//
ASSERT(FALSE);
hr = S_FALSE;
break;
}
}
return hr;
}
HRESULT
CSpdInfo::FlushLogs()
/*++
CSpdInfo::FlushLogs - Flushes logs in the data base and resets the index
manager
--*/
{
HRESULT hr = S_OK;
FreeItemsAndEmptyArray(m_arrayLogData);
m_IndexMgrLogData.Reset();
return hr;
}
DWORD
CSpdInfo::GetLogDataCount()
{
DWORD dwSize = 0;
CSingleLock cLock(&m_csData);
cLock.Lock();
dwSize = (DWORD) m_arrayLogData.GetSize();
cLock.Unlock();
return dwSize;
}
HRESULT
CSpdInfo::InternalGetSpecificLog(
CLogDataInfo *pLogDataInfo
)
/*++
CSpdInfo::InternalGetSpecificLog: Internal function to retrieve all fields
of requested record
Arguments:
[in/out] pLogDataInfo - On entry has the partial record,
On exit has the complete record if successful
Returns:
S_OK on Success
--*/
{
HRESULT hr = S_OK;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwNumRecords = 0;
WZC_DB_RECORD wzcTemplate;
PWZC_DB_RECORD pwzcRecordList = NULL;
if (false == m_session_init)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
goto Error;
}
memset(&wzcTemplate, 0, sizeof(WZC_DB_RECORD));
//Fill up template
dwErr = pLogDataInfo->ConvertToDbRecord(&wzcTemplate);
if (dwErr != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwErr);
goto Error;
}
dwErr = GetSpecificLogRecord(m_session,
&wzcTemplate,
&pwzcRecordList,
&dwNumRecords,
NULL);
if (dwErr != ERROR_SUCCESS)
{
hr = HRESULT_FROM_WIN32(dwErr);
goto FreeOnError;
}
if (dwNumRecords != 1)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
goto FreeOnError;
}
//Fill up return value
*pLogDataInfo = pwzcRecordList[0];
FreeOnError:
DeallocateDbRecord(&wzcTemplate);
COM_PROTECT_ERROR_LABEL;
return hr;
}
HRESULT
CSpdInfo::GetSpecificLog(
int iIndex,
CLogDataInfo *pLogData
)
/*++
CSpdInfo::GetSpecificLog: Gets a specific log from the database with all
information
Arguments:
[in] iIndex - Index to the record to obtain
[out] pLogData - Storage for the specific record, contains the complete
record on success
Returns:
S_OK on success
--*/
{
HRESULT hr = S_OK;
int nSize = 0;
CLogDataInfo *pLogDataInfo = NULL;
m_csData.Lock();
nSize = (DWORD)m_arrayLogData.GetSize();
if ((iIndex < 0) || (iIndex >= nSize))
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
goto Error;
}
pLogDataInfo = (CLogDataInfo*)m_IndexMgrLogData.GetItemData(iIndex);
if (NULL == pLogDataInfo)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto Error;
}
//Get the complete record
*pLogData = *pLogDataInfo;
CORg(InternalGetSpecificLog(pLogData));
COM_PROTECT_ERROR_LABEL;
m_csData.Unlock();
return hr;
}
HRESULT
CSpdInfo::GetLogDataInfo(
int iIndex,
CLogDataInfo * pLogData
)
{
HRESULT hr = S_OK;
int nSize = 0;
CLogDataInfo *pLogDataInfo = NULL;
m_csData.Lock();
nSize = (DWORD)m_arrayLogData.GetSize();
if ((iIndex < 0) || (iIndex >= nSize))
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
goto Error;
}
pLogDataInfo = (CLogDataInfo*)m_IndexMgrLogData.GetItemData(iIndex);
if (NULL == pLogDataInfo)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto Error;
}
//Get the partial record
*pLogData = *pLogDataInfo;
COM_PROTECT_ERROR_LABEL;
m_csData.Unlock();
return hr;
}
HRESULT
CSpdInfo::SortLogData(
DWORD dwIndexType,
DWORD dwSortOptions
)
{
return m_IndexMgrLogData.SortLogData(dwIndexType, dwSortOptions);
}
HRESULT CSpdInfo::SortLogData()
/*++
CSpdInfo::SortLogData
Description: For use externally, locks and sorts with last set sort
options
Parameters:
Returns:
--*/
{
HRESULT hr = S_OK;
m_csData.Lock();
hr = SortLogData(m_dwSortIndex, m_dwSortOption);
m_csData.Unlock();
return hr;
}
HRESULT
CSpdInfo::SetSortOptions(
DWORD dwColID,
BOOL bAscending
)
/*++
CSpdInfo::SetSortOptions
Sets the sort options to be used whenever data is enumerated
--*/
{
HRESULT hr = S_OK;
DWORD dwSortOption = SORT_ASCENDING;
if( (IDS_COL_LOGDATA_TIME != dwColID) &&
(IDS_COL_LOGDATA_COMP_ID != dwColID) &&
(IDS_COL_LOGDATA_CAT != dwColID) &&
(IDS_COL_LOGDATA_LOCAL_MAC_ADDR != dwColID) &&
(IDS_COL_LOGDATA_REMOTE_MAC_ADDR != dwColID) &&
(IDS_COL_LOGDATA_SSID != dwColID) &&
(IDS_COL_LOGDATA_MSG != dwColID) )
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto done;
}
if (FALSE == bAscending)
dwSortOption = SORT_DESCENDING;
//lock csData so that EnumLogRecords sorts correctly on the next sort
m_csData.Lock();
m_dwSortIndex = dwColID;
m_dwSortOption = dwSortOption;
m_csData.Unlock();
done:
return hr;
}
HRESULT
CSpdInfo::FindIndex(
int *pnIndex,
CLogDataInfo *pLogDataInfo
)
/*++
CSpdInfo::FindIndex
Finds the virtual index of the item corresponding to the input LogDataInfo
Parameters:
[out] pnIndex - A pointer to place the result index
[in] pLogDataInfo - A pointer to the LogDataInfo to be found
Returns:
S_OK on success
*pnIndex will contain a valid index if found, else will have -1
--*/
{
int nSize = 0;
int i = 0;
HRESULT hr = S_OK;
BOOL bFound = FALSE;
CLogDataInfo *pLogDataLHS = NULL;
if ( (NULL == pnIndex) || (NULL == pLogDataInfo) )
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto Error;
}
*pnIndex = -1;
m_csData.Lock();
nSize = (int) m_arrayLogData.GetSize();
while ( (i < nSize) && (FALSE == bFound) )
{
pLogDataLHS = (CLogDataInfo*) m_IndexMgrLogData.GetItemData(i);
if (*pLogDataLHS == *pLogDataInfo)
{
*pnIndex = i;
bFound = TRUE;
}
else
i++;
}
m_csData.Unlock();
COM_PROTECT_ERROR_LABEL;
return hr;
}
HRESULT
CSpdInfo::GetLastIndex(
int *pnIndex
)
/*++
CSpdInfo::GetLastIndex
Returns the virtual index for the last item in the list
Returns:
S_OK on success
--*/
{
int nLastIndex = 0;
HRESULT hr = S_OK;
if (NULL == pnIndex)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto Error;
}
m_csData.Lock();
nLastIndex = (int) m_arrayLogData.GetSize();
nLastIndex--;
*pnIndex = nLastIndex;
m_csData.Unlock();
COM_PROTECT_ERROR_LABEL;
return hr;
}
STDMETHODIMP
CSpdInfo::Destroy()
{
//$REVIEW this routine get called when doing auto-refresh
//We don't need to clean up anything at this time.
//Each array (Filter, SA, policy...) will get cleaned up when calling the
//corresponding enum function.
HANDLE hSession;
GetSession(&hSession);
if (m_session_init == true)
{
CloseWZCDbLogSession(hSession);
m_session_init = false;
m_bFromFirst = TRUE;
}
return S_OK;
}
DWORD
CSpdInfo::GetInitInfo()
{
CSingleLock cLock(&m_csData);
cLock.Lock();
return m_Init;
}
void
CSpdInfo::SetInitInfo(
DWORD dwInitInfo
)
{
CSingleLock cLock(&m_csData);
cLock.Lock();
m_Init=dwInitInfo;
}
DWORD
CSpdInfo::GetActiveInfo()
{
CSingleLock cLock(&m_csData);
cLock.Lock();
return m_Active;
}
void
CSpdInfo::SetActiveInfo(
DWORD dwActiveInfo
)
{
CSingleLock cLock(&m_csData);
cLock.Lock();
m_Active=dwActiveInfo;
}
/*!--------------------------------------------------------------------------
CreateSpdInfo
Helper to create the SpdInfo object.
---------------------------------------------------------------------------*/
HRESULT
CreateSpdInfo(
ISpdInfo ** ppSpdInfo
)
{
AFX_MANAGE_STATE(AfxGetModuleState());
SPISpdInfo spSpdInfo;
ISpdInfo * pSpdInfo = NULL;
HRESULT hr = hrOK;
COM_PROTECT_TRY
{
pSpdInfo = new CSpdInfo;
// Do this so that it will get freed on error
spSpdInfo = pSpdInfo;
*ppSpdInfo = spSpdInfo.Transfer();
}
COM_PROTECT_CATCH
return hr;
}
DWORD
DeallocateDbRecord(
PWZC_DB_RECORD const pwzcRec
)
/*++
DeallocateDbRecord - Frees up the internal memory used in a WZC_DB_RECORD
structure. To be used only when space has been allocated by sources other
than RPC. Does not deallocate outer level
Arguments:
[in/out]pwzcRec - Holds the record to free. Internal mem alone is freed and
contents freed are annulled.
Returns:
ERROR_SUCCESS on success
--*/
{
DWORD dwErr = ERROR_SUCCESS;
if (NULL != pwzcRec->message.pData)
{
delete [] pwzcRec->message.pData;
pwzcRec->message.pData = NULL;
}
if (NULL != pwzcRec->localmac.pData)
{
delete [] pwzcRec->localmac.pData;
pwzcRec->localmac.pData = NULL;
}
if (NULL != pwzcRec->remotemac.pData)
{
delete [] pwzcRec->remotemac.pData;
pwzcRec->remotemac.pData = NULL;
}
if (NULL != pwzcRec->ssid.pData)
{
delete [] pwzcRec->ssid.pData;
pwzcRec->ssid.pData = NULL;
}
if (NULL != pwzcRec->context.pData)
{
delete [] pwzcRec->context.pData;
pwzcRec->ssid.pData = NULL;
}
return dwErr;
}
//
// FUNCTIONS: MIDL_user_allocate and MIDL_user_free
//
// PURPOSE: Used by stubs to allocate and free memory
// in standard RPC calls. Not used when
// [enable_allocate] is specified in the .acf.
//
//
// PARAMETERS:
// See documentations.
//
// RETURN VALUE:
// Exceptions on error. This is not required,
// you can use -error allocation on the midl.exe
// command line instead.
//
//
void * __RPC_USER MIDL_user_allocate(size_t size)
{
return(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size));
}
void __RPC_USER MIDL_user_free( void *pointer)
{
HeapFree(GetProcessHeap(), 0, pointer);
}