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

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. spddb.h
  7. FILE HISTORY:
  8. */
  9. #include "stdafx.h"
  10. #include "DynamLnk.h"
  11. #include "spddb.h"
  12. #include "spdutil.h"
  13. #include "security.h"
  14. #include "lm.h"
  15. #include "service.h"
  16. #define AVG_PREFERRED_ENUM_COUNT 40
  17. #define MAX_NUM_RECORDS 10 // was 10
  18. #define DEFAULT_SECURITY_PKG _T("negotiate")
  19. #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
  20. #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
  21. //
  22. // The database holds 5K records and wraps around. So we dont cache more than
  23. // 5K records.
  24. //
  25. #define WZCDB_DEFAULT_NUM_RECS 5000
  26. // internal functions
  27. BOOL IsUserAdmin(LPCTSTR pszMachine, PSID AccountSid);
  28. BOOL LookupAliasFromRid(LPWSTR TargetComputer, DWORD Rid, LPWSTR Name, PDWORD cchName);
  29. DWORD ValidateDomainAccount(IN CString Machine, IN CString UserName, IN CString Domain, OUT PSID * AccountSid);
  30. NTSTATUS ValidatePassword(IN LPCWSTR UserName, IN LPCWSTR Domain, IN LPCWSTR Password);
  31. DWORD GetCurrentUser(CString & strAccount);
  32. DWORD GetCurrentUser(CString & strAccount)
  33. {
  34. LPBYTE pBuf;
  35. NET_API_STATUS status = NetWkstaUserGetInfo(NULL, 1, &pBuf);
  36. if (status == NERR_Success)
  37. {
  38. strAccount.Empty();
  39. WKSTA_USER_INFO_1 * pwkstaUserInfo = (WKSTA_USER_INFO_1 *) pBuf;
  40. strAccount = pwkstaUserInfo->wkui1_logon_domain;
  41. strAccount += _T("\\");
  42. strAccount += pwkstaUserInfo->wkui1_username;
  43. NetApiBufferFree(pBuf);
  44. }
  45. return (DWORD) status;
  46. }
  47. /*!--------------------------------------------------------------------------
  48. IsAdmin
  49. Connect to the remote machine as administrator with user-supplied
  50. credentials to see if the user has admin priviledges
  51. Returns
  52. TRUE - the user has admin rights
  53. FALSE - if user doesn't
  54. Author: EricDav, KennT
  55. ---------------------------------------------------------------------------*/
  56. DWORD IsAdmin(LPCTSTR szMachineName, LPCTSTR szAccount, LPCTSTR szPassword, BOOL * pIsAdmin)
  57. {
  58. CString stAccount;
  59. CString stDomain;
  60. CString stUser;
  61. CString stMachineName;
  62. DWORD dwStatus;
  63. BOOL fIsAdmin = FALSE;
  64. // get the current user info
  65. if (szAccount == NULL)
  66. {
  67. GetCurrentUser(stAccount);
  68. }
  69. else
  70. {
  71. stAccount = szAccount;
  72. }
  73. // separate the user and domain
  74. int nPos = stAccount.Find(_T("\\"));
  75. stDomain = stAccount.Left(nPos);
  76. stUser = stAccount.Right(stAccount.GetLength() - nPos - 1);
  77. // build the machine string
  78. stMachineName = szMachineName;
  79. if ( stMachineName.Left(2) != TEXT( "\\\\" ) )
  80. {
  81. stMachineName = TEXT( "\\\\" ) + stMachineName;
  82. }
  83. // validate the domain account and get the sid
  84. PSID connectSid;
  85. dwStatus = ValidateDomainAccount( stMachineName, stUser, stDomain, &connectSid );
  86. if ( dwStatus != ERROR_SUCCESS )
  87. {
  88. goto Error;
  89. }
  90. // if a password was supplied, is it correct?
  91. if (szPassword)
  92. {
  93. dwStatus = ValidatePassword( stUser, stDomain, szPassword );
  94. if ( dwStatus != SEC_E_OK )
  95. {
  96. switch ( dwStatus )
  97. {
  98. case SEC_E_LOGON_DENIED:
  99. dwStatus = ERROR_INVALID_PASSWORD;
  100. break;
  101. case SEC_E_INVALID_HANDLE:
  102. dwStatus = ERROR_INTERNAL_ERROR;
  103. break;
  104. default:
  105. dwStatus = ERROR_INTERNAL_ERROR;
  106. break;
  107. } // end of switch
  108. goto Error;
  109. } // Did ValidatePassword succeed?
  110. }
  111. // now check the machine to see if this account has admin access
  112. fIsAdmin = IsUserAdmin( stMachineName, connectSid );
  113. Error:
  114. if (pIsAdmin)
  115. *pIsAdmin = fIsAdmin;
  116. return dwStatus;
  117. }
  118. BOOL
  119. IsUserAdmin(LPCTSTR pszMachine,
  120. PSID AccountSid)
  121. /*++
  122. Routine Description:
  123. Determine if the specified account is a member of the local admin's group
  124. Arguments:
  125. AccountSid - pointer to service account Sid
  126. Return Value:
  127. True if member
  128. --*/
  129. {
  130. NET_API_STATUS status;
  131. DWORD count;
  132. WCHAR adminGroupName[UNLEN+1];
  133. DWORD cchName = UNLEN;
  134. PLOCALGROUP_MEMBERS_INFO_0 grpMemberInfo;
  135. PLOCALGROUP_MEMBERS_INFO_0 pInfo;
  136. DWORD entriesRead;
  137. DWORD totalEntries;
  138. DWORD_PTR resumeHandle = NULL;
  139. DWORD bufferSize = 128;
  140. BOOL foundEntry = FALSE;
  141. // get the name of the admin's group
  142. if (!LookupAliasFromRid(NULL,
  143. DOMAIN_ALIAS_RID_ADMINS,
  144. adminGroupName,
  145. &cchName)) {
  146. return(FALSE);
  147. }
  148. // get the Sids of the members of the admin's group
  149. do
  150. {
  151. status = NetLocalGroupGetMembers(pszMachine,
  152. adminGroupName,
  153. 0, // level 0 - just the Sid
  154. (LPBYTE *)&grpMemberInfo,
  155. bufferSize,
  156. &entriesRead,
  157. &totalEntries,
  158. &resumeHandle);
  159. bufferSize *= 2;
  160. if ( status == ERROR_MORE_DATA )
  161. {
  162. // we got some of the data but I want it all; free this buffer and
  163. // reset the context handle for the API
  164. NetApiBufferFree( grpMemberInfo );
  165. resumeHandle = NULL;
  166. }
  167. } while ( status == NERR_BufTooSmall || status == ERROR_MORE_DATA );
  168. if ( status == NERR_Success )
  169. {
  170. // loop through the members of the admin group, comparing the supplied
  171. // Sid to that of the group members' Sids
  172. for ( count = 0, pInfo = grpMemberInfo; count < totalEntries; ++count, ++pInfo )
  173. {
  174. if ( EqualSid( AccountSid, pInfo->lgrmi0_sid ))
  175. {
  176. foundEntry = TRUE;
  177. break;
  178. }
  179. }
  180. NetApiBufferFree( grpMemberInfo );
  181. }
  182. return foundEntry;
  183. }
  184. //
  185. //
  186. //
  187. BOOL
  188. LookupAliasFromRid(
  189. LPWSTR TargetComputer,
  190. DWORD Rid,
  191. LPWSTR Name,
  192. PDWORD cchName
  193. )
  194. {
  195. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  196. SID_NAME_USE snu;
  197. PSID pSid;
  198. WCHAR DomainName[DNLEN+1];
  199. DWORD cchDomainName = DNLEN;
  200. BOOL bSuccess = FALSE;
  201. //
  202. // Sid is the same regardless of machine, since the well-known
  203. // BUILTIN domain is referenced.
  204. //
  205. if(AllocateAndInitializeSid(&sia,
  206. 2,
  207. SECURITY_BUILTIN_DOMAIN_RID,
  208. Rid,
  209. 0, 0, 0, 0, 0, 0,
  210. &pSid)) {
  211. bSuccess = LookupAccountSidW(TargetComputer,
  212. pSid,
  213. Name,
  214. cchName,
  215. DomainName,
  216. &cchDomainName,
  217. &snu);
  218. FreeSid(pSid);
  219. }
  220. return bSuccess;
  221. } // LookupAliasFromRid
  222. DWORD
  223. ValidateDomainAccount(
  224. IN CString Machine,
  225. IN CString UserName,
  226. IN CString Domain,
  227. OUT PSID * AccountSid
  228. )
  229. /*++
  230. Routine Description:
  231. For the given credentials, look up the account SID for the specified
  232. domain. As a side effect, the Sid is stored in theData->m_Sid.
  233. Arguments:
  234. pointers to strings that describe the user name, domain name, and password
  235. AccountSid - address of pointer that receives the SID for this user
  236. Return Value:
  237. TRUE if everything validated ok.
  238. --*/
  239. {
  240. DWORD dwStatus = ERROR_SUCCESS;
  241. DWORD dwSidSize = 128;
  242. DWORD dwDomainNameSize = 128;
  243. LPWSTR pwszDomainName;
  244. SID_NAME_USE SidType;
  245. CString domainAccount;
  246. PSID accountSid;
  247. domainAccount = Domain + _T("\\") + UserName;
  248. do {
  249. // Attempt to allocate a buffer for the SID. Note that apparently in the
  250. // absence of any error theData->m_Sid is freed only when theData goes
  251. // out of scope.
  252. accountSid = LocalAlloc( LMEM_FIXED, dwSidSize );
  253. pwszDomainName = (LPWSTR) LocalAlloc( LMEM_FIXED, dwDomainNameSize * sizeof(WCHAR) );
  254. // Was space allocated for the SID and domain name successfully?
  255. if ( accountSid == NULL || pwszDomainName == NULL ) {
  256. if ( accountSid != NULL ) {
  257. LocalFree( accountSid );
  258. }
  259. if ( pwszDomainName != NULL ) {
  260. LocalFree( pwszDomainName );
  261. }
  262. //FATALERR( IDS_ERR_NOT_ENOUGH_MEMORY, GetLastError() ); // no return
  263. break;
  264. }
  265. // Attempt to Retrieve the SID and domain name. If LookupAccountName failes
  266. // because of insufficient buffer size(s) dwSidSize and dwDomainNameSize
  267. // will be set correctly for the next attempt.
  268. if ( !LookupAccountName( Machine,
  269. domainAccount,
  270. accountSid,
  271. &dwSidSize,
  272. pwszDomainName,
  273. &dwDomainNameSize,
  274. &SidType ))
  275. {
  276. // free the Sid buffer and find out why we failed
  277. LocalFree( accountSid );
  278. dwStatus = GetLastError();
  279. }
  280. // domain name isn't needed at any time
  281. LocalFree( pwszDomainName );
  282. pwszDomainName = NULL;
  283. } while ( dwStatus == ERROR_INSUFFICIENT_BUFFER );
  284. if ( dwStatus == ERROR_SUCCESS ) {
  285. *AccountSid = accountSid;
  286. }
  287. return dwStatus;
  288. } // ValidateDomainAccount
  289. NTSTATUS
  290. ValidatePassword(
  291. IN LPCWSTR UserName,
  292. IN LPCWSTR Domain,
  293. IN LPCWSTR Password
  294. )
  295. /*++
  296. Routine Description:
  297. Uses SSPI to validate the specified password
  298. Arguments:
  299. UserName - Supplies the user name
  300. Domain - Supplies the user's domain
  301. Password - Supplies the password
  302. Return Value:
  303. TRUE if the password is valid.
  304. FALSE otherwise.
  305. --*/
  306. {
  307. SECURITY_STATUS SecStatus;
  308. SECURITY_STATUS AcceptStatus;
  309. SECURITY_STATUS InitStatus;
  310. CredHandle ClientCredHandle;
  311. CredHandle ServerCredHandle;
  312. BOOL ClientCredAllocated = FALSE;
  313. BOOL ServerCredAllocated = FALSE;
  314. CtxtHandle ClientContextHandle;
  315. CtxtHandle ServerContextHandle;
  316. TimeStamp Lifetime;
  317. ULONG ContextAttributes;
  318. PSecPkgInfo PackageInfo = NULL;
  319. ULONG ClientFlags;
  320. ULONG ServerFlags;
  321. SEC_WINNT_AUTH_IDENTITY_W AuthIdentity;
  322. SecBufferDesc NegotiateDesc;
  323. SecBuffer NegotiateBuffer;
  324. SecBufferDesc ChallengeDesc;
  325. SecBuffer ChallengeBuffer;
  326. SecBufferDesc AuthenticateDesc;
  327. SecBuffer AuthenticateBuffer;
  328. SecBufferDesc *pChallengeDesc = NULL;
  329. CtxtHandle * pClientContextHandle = NULL;
  330. CtxtHandle * pServerContextHandle = NULL;
  331. AuthIdentity.User = (LPWSTR)UserName;
  332. AuthIdentity.UserLength = lstrlenW(UserName);
  333. AuthIdentity.Domain = (LPWSTR)Domain;
  334. AuthIdentity.DomainLength = lstrlenW(Domain);
  335. AuthIdentity.Password = (LPWSTR)Password;
  336. AuthIdentity.PasswordLength = lstrlenW(Password);
  337. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  338. NegotiateBuffer.pvBuffer = NULL;
  339. ChallengeBuffer.pvBuffer = NULL;
  340. AuthenticateBuffer.pvBuffer = NULL;
  341. //
  342. // Get info about the security packages.
  343. //
  344. SecStatus = QuerySecurityPackageInfo( DEFAULT_SECURITY_PKG, &PackageInfo );
  345. if ( SecStatus != STATUS_SUCCESS ) {
  346. goto error_exit;
  347. }
  348. //
  349. // Acquire a credential handle for the server side
  350. //
  351. SecStatus = AcquireCredentialsHandle(
  352. NULL,
  353. DEFAULT_SECURITY_PKG,
  354. SECPKG_CRED_INBOUND,
  355. NULL,
  356. &AuthIdentity,
  357. NULL,
  358. NULL,
  359. &ServerCredHandle,
  360. &Lifetime );
  361. if ( SecStatus != STATUS_SUCCESS ) {
  362. goto error_exit;
  363. }
  364. ServerCredAllocated = TRUE;
  365. //
  366. // Acquire a credential handle for the client side
  367. //
  368. SecStatus = AcquireCredentialsHandle(
  369. NULL, // New principal
  370. DEFAULT_SECURITY_PKG,
  371. SECPKG_CRED_OUTBOUND,
  372. NULL,
  373. &AuthIdentity,
  374. NULL,
  375. NULL,
  376. &ClientCredHandle,
  377. &Lifetime );
  378. if ( SecStatus != STATUS_SUCCESS ) {
  379. goto error_exit;
  380. }
  381. ClientCredAllocated = TRUE;
  382. NegotiateBuffer.pvBuffer = LocalAlloc( 0, PackageInfo->cbMaxToken ); // [CHKCHK] check or allocate this earlier //
  383. if ( NegotiateBuffer.pvBuffer == NULL ) {
  384. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  385. goto error_exit;
  386. }
  387. ChallengeBuffer.pvBuffer = LocalAlloc( 0, PackageInfo->cbMaxToken ); // [CHKCHK]
  388. if ( ChallengeBuffer.pvBuffer == NULL ) {
  389. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  390. goto error_exit;
  391. }
  392. do {
  393. //
  394. // Get the NegotiateMessage (ClientSide)
  395. //
  396. NegotiateDesc.ulVersion = 0;
  397. NegotiateDesc.cBuffers = 1;
  398. NegotiateDesc.pBuffers = &NegotiateBuffer;
  399. NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
  400. NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken;
  401. ClientFlags = 0; // ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT; // [CHKCHK] 0
  402. InitStatus = InitializeSecurityContext(
  403. &ClientCredHandle,
  404. pClientContextHandle, // (NULL on the first pass, partially formed ctx on the next)
  405. NULL, // [CHKCHK] szTargetName
  406. ClientFlags,
  407. 0, // Reserved 1
  408. SECURITY_NATIVE_DREP,
  409. pChallengeDesc, // (NULL on the first pass)
  410. 0, // Reserved 2
  411. &ClientContextHandle,
  412. &NegotiateDesc,
  413. &ContextAttributes,
  414. &Lifetime );
  415. // BUGBUG - the following call to NT_SUCCESS should be replaced with something.
  416. if ( !NT_SUCCESS(InitStatus) ) {
  417. SecStatus = InitStatus;
  418. goto error_exit;
  419. }
  420. // ValidateBuffer( &NegotiateDesc ) // [CHKCHK]
  421. pClientContextHandle = &ClientContextHandle;
  422. //
  423. // Get the ChallengeMessage (ServerSide)
  424. //
  425. NegotiateBuffer.BufferType |= SECBUFFER_READONLY;
  426. ChallengeDesc.ulVersion = 0;
  427. ChallengeDesc.cBuffers = 1;
  428. ChallengeDesc.pBuffers = &ChallengeBuffer;
  429. ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken;
  430. ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
  431. ServerFlags = ASC_REQ_ALLOW_NON_USER_LOGONS; // ASC_REQ_EXTENDED_ERROR; [CHKCHK]
  432. AcceptStatus = AcceptSecurityContext(
  433. &ServerCredHandle,
  434. pServerContextHandle, // (NULL on the first pass)
  435. &NegotiateDesc,
  436. ServerFlags,
  437. SECURITY_NATIVE_DREP,
  438. &ServerContextHandle,
  439. &ChallengeDesc,
  440. &ContextAttributes,
  441. &Lifetime );
  442. // BUGBUG - the following call to NT_SUCCESS should be replaced with something.
  443. if ( !NT_SUCCESS(AcceptStatus) ) {
  444. SecStatus = AcceptStatus;
  445. goto error_exit;
  446. }
  447. // ValidateBuffer( &NegotiateDesc ) // [CHKCHK]
  448. pChallengeDesc = &ChallengeDesc;
  449. pServerContextHandle = &ServerContextHandle;
  450. } while ( AcceptStatus == SEC_I_CONTINUE_NEEDED ); // || InitStatus == SEC_I_CONTINUE_NEEDED );
  451. error_exit:
  452. if (ServerCredAllocated) {
  453. FreeCredentialsHandle( &ServerCredHandle );
  454. }
  455. if (ClientCredAllocated) {
  456. FreeCredentialsHandle( &ClientCredHandle );
  457. }
  458. //
  459. // Final Cleanup
  460. //
  461. if ( NegotiateBuffer.pvBuffer != NULL ) {
  462. (VOID) LocalFree( NegotiateBuffer.pvBuffer );
  463. }
  464. if ( ChallengeBuffer.pvBuffer != NULL ) {
  465. (VOID) LocalFree( ChallengeBuffer.pvBuffer );
  466. }
  467. if ( AuthenticateBuffer.pvBuffer != NULL ) {
  468. (VOID) LocalFree( AuthenticateBuffer.pvBuffer );
  469. }
  470. return(SecStatus);
  471. } // ValidatePassword
  472. DEBUG_DECLARE_INSTANCE_COUNTER(CSpdInfo);
  473. CSpdInfo::CSpdInfo()
  474. : m_cRef(1),
  475. m_Init(0),
  476. m_Active(0),
  477. m_session_init(false),
  478. m_dwSortIndex(IDS_COL_LOGDATA_TIME),
  479. m_dwSortOption(SORT_ASCENDING),
  480. m_nNumRecords(WZCDB_DEFAULT_NUM_RECS),
  481. m_bEliminateDuplicates(FALSE)
  482. {
  483. HRESULT hr = S_OK;
  484. HANDLE hSession = NULL;
  485. /*
  486. Either we opened a session successfully or we found out that logging
  487. is disabled. If logging is disabled then we check every time EnumLogData
  488. is called to see if we can access the database.
  489. */
  490. DEBUG_INCREMENT_INSTANCE_COUNTER(CSpdInfo);
  491. }
  492. CSpdInfo::~CSpdInfo()
  493. {
  494. DEBUG_DECREMENT_INSTANCE_COUNTER(CSpdInfo);
  495. CSingleLock cLock(&m_csData);
  496. cLock.Lock();
  497. //Convert the data to our internal data structure
  498. //FreeItemsAndEmptyArray(m_arrayFWFilters);
  499. FreeItemsAndEmptyArray(m_arrayLogData);
  500. cLock.Unlock();
  501. }
  502. // Although this object is not a COM Interface, we want to be able to
  503. // take advantage of recounting, so we have basic addref/release/QI support
  504. IMPLEMENT_ADDREF_RELEASE(CSpdInfo)
  505. IMPLEMENT_SIMPLE_QUERYINTERFACE(CSpdInfo, ISpdInfo)
  506. void
  507. CSpdInfo::FreeItemsAndEmptyArray(
  508. CLogDataInfoArray& array
  509. )
  510. {
  511. for (int i = 0; i < array.GetSize(); i++)
  512. {
  513. delete array.GetAt(i);
  514. }
  515. array.RemoveAll();
  516. }
  517. HRESULT
  518. CSpdInfo::SetComputerName(
  519. LPTSTR pszName
  520. )
  521. {
  522. m_stMachineName = pszName;
  523. return S_OK;
  524. }
  525. HRESULT
  526. CSpdInfo::GetComputerName(
  527. CString * pstName
  528. )
  529. {
  530. Assert(pstName);
  531. if (NULL == pstName)
  532. return E_INVALIDARG;
  533. *pstName = m_stMachineName;
  534. return S_OK;
  535. }
  536. HRESULT
  537. CSpdInfo::GetSession(
  538. PHANDLE phsession
  539. )
  540. {
  541. Assert(session);
  542. if (NULL == phsession)
  543. return E_INVALIDARG;
  544. *phsession = m_session;
  545. return S_OK;
  546. }
  547. HRESULT
  548. CSpdInfo::SetSession(
  549. HANDLE hsession
  550. )
  551. {
  552. m_csData.Lock();
  553. m_session = hsession;
  554. m_session_init = true;
  555. m_bFromFirst = TRUE;
  556. m_csData.Unlock();
  557. return S_OK;
  558. }
  559. HRESULT
  560. CSpdInfo::ResetSession()
  561. /*++
  562. CSpdInfo::ResetSession:
  563. Used to reset the session when the logging is turned off so that we dont
  564. use a bad session.
  565. Arguments:
  566. None
  567. Returns:
  568. Always returns S_OK
  569. --*/
  570. {
  571. if (m_session != NULL)
  572. CloseWZCDbLogSession(m_session);
  573. m_session = NULL;
  574. m_session_init = false;
  575. return S_OK;
  576. }
  577. DWORD
  578. CSpdInfo::EliminateDuplicates(
  579. CLogDataInfoArray *pArray
  580. )
  581. /*++
  582. CSpdInfo::EliminateDuplicates: Removes duplicate records from the given
  583. array.
  584. If the database moves past the end of the table, it cannot move
  585. to get new records on the next refresh cyle, hence it always remains
  586. on the last record. So if our cache size is the same as the database
  587. size, then we must delete the first record as the new enumeration
  588. would have resulted in a duplicate record.
  589. We also know that in only the first element is a duplicate
  590. Arguments:
  591. [in/out] pArray - Pointer to array containing elements. On exit contains
  592. all non duplicate elements
  593. Returns:
  594. ERROR_SUCCESS on success
  595. --*/
  596. {
  597. int i = 0;
  598. int j = 0;
  599. int nSize = 0;
  600. DWORD dwErr = ERROR_SUCCESS;
  601. CLogDataInfo *pLog = NULL;
  602. if (NULL == pArray)
  603. {
  604. dwErr = ERROR_INVALID_PARAMETER;
  605. goto done;
  606. }
  607. nSize = (int) pArray->GetSize();
  608. if (0 == nSize)
  609. goto done;
  610. //Merely delete the first element
  611. pLog = pArray->GetAt(0);
  612. delete pLog;
  613. pArray->RemoveAt(0);
  614. done:
  615. return dwErr;
  616. }
  617. void
  618. CSpdInfo::StartFromFirstRecord(
  619. BOOL bFromFirst)
  620. /*++
  621. Routine Description:
  622. CSpdInfo::StartFromFirstRecord:
  623. Sets the read location to start from the first or from the end of the
  624. table
  625. Arguments:
  626. IN bFromFirst - TRUE if the read should be done from the beginning of the
  627. database, FALSE otherwise
  628. Returns:
  629. Nothing.
  630. --*/
  631. {
  632. m_csData.Lock();
  633. m_bFromFirst = bFromFirst;
  634. m_csData.Unlock();
  635. }
  636. HRESULT
  637. CSpdInfo::InternalEnumLogData(
  638. CLogDataInfoArray *pArray,
  639. DWORD dwPreferredNum,
  640. BOOL bFromFirst
  641. )
  642. /*++
  643. Routine Description:
  644. CSpdInfo::InternalEnumLogData - Enumerates data from the service and adds
  645. to pArray.
  646. Arguments:
  647. [out] pArray - New values are appended if any
  648. [in] dwPreferredNum - Holds the number of records requested
  649. Returns:
  650. HRESULT_FROM_WIN32() of the following codes
  651. ERROR_SUCCESS on success
  652. ERROR_NO_MORE_ITEMS on no more items
  653. ERROR_SERVICE_DISABLED otherwise
  654. --*/
  655. {
  656. HRESULT hr = hrOK;
  657. DWORD dwErr = ERROR_SUCCESS;
  658. HANDLE hsession = NULL;
  659. DWORD dwCrtNum = 0;
  660. PWZC_DB_RECORD pDbRecord = NULL;
  661. PWZC_DB_RECORD pWZCRecords = NULL;
  662. DWORD dwNumRecords = 0;
  663. CLogDataInfo *pLogDataInfo = NULL;
  664. int i = 0;
  665. ASSERT(pArray);
  666. FreeItemsAndEmptyArray(*pArray);
  667. GetSession(&hsession);
  668. while (ERROR_SUCCESS == dwErr)
  669. {
  670. dwCrtNum = (DWORD)pArray->GetSize();
  671. dwErr = EnumWZCDbLogRecords(hsession,
  672. NULL,
  673. &bFromFirst,
  674. dwPreferredNum,
  675. &pWZCRecords,
  676. &dwNumRecords,
  677. NULL);
  678. bFromFirst = FALSE;
  679. pArray->SetSize(dwCrtNum + dwNumRecords);
  680. for (i = 0, pDbRecord = pWZCRecords;
  681. i < (int)dwNumRecords;
  682. i++, pDbRecord++)
  683. {
  684. pLogDataInfo = new CLogDataInfo;
  685. if (NULL == pLogDataInfo)
  686. {
  687. hr = E_OUTOFMEMORY;
  688. goto Error;
  689. }
  690. *pLogDataInfo = *pDbRecord;
  691. (*pArray)[dwCrtNum + i] = pLogDataInfo;
  692. RpcFree(pDbRecord->message.pData);
  693. RpcFree(pDbRecord->context.pData);
  694. RpcFree(pDbRecord->ssid.pData);
  695. RpcFree(pDbRecord->remotemac.pData);
  696. RpcFree(pDbRecord->localmac.pData);
  697. }
  698. RpcFree(pWZCRecords);
  699. }
  700. switch (dwErr)
  701. {
  702. case ERROR_SUCCESS:
  703. case ERROR_NO_MORE_ITEMS:
  704. hr = HRESULT_FROM_WIN32(ERROR_SUCCESS);
  705. break;
  706. default:
  707. hr = HRESULT_FROM_WIN32(dwErr);
  708. break;
  709. }
  710. COM_PROTECT_ERROR_LABEL;
  711. return hr;
  712. }
  713. HRESULT
  714. CSpdInfo::EnumLogData(
  715. PDWORD pdwNew,
  716. PDWORD pdwTotal)
  717. /*++
  718. Routine Description:
  719. CSpdInfo::EnumLogData:
  720. Enumerates logs differentially
  721. Arguments:
  722. Returns:
  723. --*/
  724. {
  725. int i = 0;
  726. int nStoreSize = 0;
  727. int nTempStoreSize = 0;
  728. int nNumToDel = 0;
  729. HRESULT hr = hrOK;
  730. DWORD dwErr = ERROR_SUCCESS;
  731. DWORD dwCurrentIndexType = 0;
  732. DWORD dwCurrentSortOption = 0;
  733. DWORD dwNumRequest = MAX_NUM_RECORDS;
  734. DWORD dwOffset = 0;
  735. DWORD dwStoreSize = 0;
  736. HANDLE hSession = NULL;
  737. CLogDataInfo *pLogInfo = NULL;
  738. CLogDataInfoArray arrayTemp;
  739. BOOL bFromFirst = FALSE;
  740. if (false == m_session_init)
  741. {
  742. dwErr = OpenWZCDbLogSession(
  743. NULL/*(LPTSTR)(LPCTSTR)m_stMachineName*/,
  744. 0,
  745. &hSession);
  746. if (dwErr != ERROR_SUCCESS)
  747. {
  748. hr = HRESULT_FROM_WIN32(dwErr);
  749. goto Error;
  750. }
  751. SetSession(hSession);
  752. }
  753. ASSERT(m_session_init == true);
  754. //
  755. // If our session was created successfully, we should go ahead and pick up
  756. // data from the database. If not we should return.
  757. //
  758. dwStoreSize = GetLogDataCount();
  759. if (dwStoreSize == 0)
  760. bFromFirst = TRUE;
  761. CORg(InternalEnumLogData(&arrayTemp, dwNumRequest, bFromFirst));
  762. m_csData.Lock();
  763. nTempStoreSize = (int) arrayTemp.GetSize();
  764. if (pdwNew != NULL)
  765. *pdwNew = nTempStoreSize;
  766. //
  767. // Add new items to our cache. If we have read records our earlier, remove
  768. // the first element from the new array, as the database would return the
  769. // last record once again.
  770. //
  771. if (nTempStoreSize > 0)
  772. {
  773. if (bFromFirst == FALSE)
  774. EliminateDuplicates(&arrayTemp);
  775. m_arrayLogData.Append(arrayTemp);
  776. }
  777. //
  778. // Delete the old items if we are at the window
  779. //
  780. nStoreSize = (int) m_arrayLogData.GetSize();
  781. if (nStoreSize >= m_nNumRecords)
  782. {
  783. nNumToDel = nStoreSize - m_nNumRecords;
  784. //
  785. // The oldest elements are at zero
  786. //
  787. for (i=0; i < nNumToDel; i++)
  788. delete m_arrayLogData.GetAt(i);
  789. m_arrayLogData.RemoveAt(0, nNumToDel);
  790. ASSERT(m_nNumRecords == m_arrayLogData.GetSize());
  791. nStoreSize = m_nNumRecords;
  792. }
  793. if (pdwTotal != NULL)
  794. *pdwTotal = nStoreSize;
  795. m_IndexMgrLogData.Reset();
  796. for (i = 0; i < nStoreSize; i++)
  797. {
  798. pLogInfo = m_arrayLogData.GetAt(i);
  799. m_IndexMgrLogData.AddItem(pLogInfo);
  800. }
  801. //
  802. // Re-sort based on the IndexType and Sort options
  803. //
  804. SortLogData(m_dwSortIndex, m_dwSortOption);
  805. m_csData.Unlock();
  806. COM_PROTECT_ERROR_LABEL;
  807. if (FAILED(hr))
  808. {
  809. switch (hr)
  810. {
  811. case HRESULT_FROM_WIN32(ERROR_REMOTE_SESSION_LIMIT_EXCEEDED):
  812. //
  813. // Pop up a message...
  814. //
  815. AfxMessageBox(
  816. IDS_ERR_SPD_UNAVAILABLE,
  817. MB_OK | MB_ICONEXCLAMATION,
  818. 0);
  819. case HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED):
  820. //
  821. // Reset the session if initialised
  822. //
  823. if (m_session_init == true)
  824. ResetSession();
  825. //
  826. // Flush the logs
  827. //
  828. FlushLogs();
  829. hr = S_OK;
  830. break;
  831. default:
  832. //
  833. // Unexpected error, this should never happen.
  834. //
  835. ASSERT(FALSE);
  836. hr = S_FALSE;
  837. break;
  838. }
  839. }
  840. return hr;
  841. }
  842. HRESULT
  843. CSpdInfo::FlushLogs()
  844. /*++
  845. CSpdInfo::FlushLogs - Flushes logs in the data base and resets the index
  846. manager
  847. --*/
  848. {
  849. HRESULT hr = S_OK;
  850. FreeItemsAndEmptyArray(m_arrayLogData);
  851. m_IndexMgrLogData.Reset();
  852. return hr;
  853. }
  854. DWORD
  855. CSpdInfo::GetLogDataCount()
  856. {
  857. DWORD dwSize = 0;
  858. CSingleLock cLock(&m_csData);
  859. cLock.Lock();
  860. dwSize = (DWORD) m_arrayLogData.GetSize();
  861. cLock.Unlock();
  862. return dwSize;
  863. }
  864. HRESULT
  865. CSpdInfo::InternalGetSpecificLog(
  866. CLogDataInfo *pLogDataInfo
  867. )
  868. /*++
  869. CSpdInfo::InternalGetSpecificLog: Internal function to retrieve all fields
  870. of requested record
  871. Arguments:
  872. [in/out] pLogDataInfo - On entry has the partial record,
  873. On exit has the complete record if successful
  874. Returns:
  875. S_OK on Success
  876. --*/
  877. {
  878. HRESULT hr = S_OK;
  879. DWORD dwErr = ERROR_SUCCESS;
  880. DWORD dwNumRecords = 0;
  881. WZC_DB_RECORD wzcTemplate;
  882. PWZC_DB_RECORD pwzcRecordList = NULL;
  883. if (false == m_session_init)
  884. {
  885. hr = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
  886. goto Error;
  887. }
  888. memset(&wzcTemplate, 0, sizeof(WZC_DB_RECORD));
  889. //Fill up template
  890. dwErr = pLogDataInfo->ConvertToDbRecord(&wzcTemplate);
  891. if (dwErr != ERROR_SUCCESS)
  892. {
  893. hr = HRESULT_FROM_WIN32(dwErr);
  894. goto Error;
  895. }
  896. dwErr = GetSpecificLogRecord(m_session,
  897. &wzcTemplate,
  898. &pwzcRecordList,
  899. &dwNumRecords,
  900. NULL);
  901. if (dwErr != ERROR_SUCCESS)
  902. {
  903. hr = HRESULT_FROM_WIN32(dwErr);
  904. goto FreeOnError;
  905. }
  906. if (dwNumRecords != 1)
  907. {
  908. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  909. goto FreeOnError;
  910. }
  911. //Fill up return value
  912. *pLogDataInfo = pwzcRecordList[0];
  913. FreeOnError:
  914. DeallocateDbRecord(&wzcTemplate);
  915. COM_PROTECT_ERROR_LABEL;
  916. return hr;
  917. }
  918. HRESULT
  919. CSpdInfo::GetSpecificLog(
  920. int iIndex,
  921. CLogDataInfo *pLogData
  922. )
  923. /*++
  924. CSpdInfo::GetSpecificLog: Gets a specific log from the database with all
  925. information
  926. Arguments:
  927. [in] iIndex - Index to the record to obtain
  928. [out] pLogData - Storage for the specific record, contains the complete
  929. record on success
  930. Returns:
  931. S_OK on success
  932. --*/
  933. {
  934. HRESULT hr = S_OK;
  935. int nSize = 0;
  936. CLogDataInfo *pLogDataInfo = NULL;
  937. m_csData.Lock();
  938. nSize = (DWORD)m_arrayLogData.GetSize();
  939. if ((iIndex < 0) || (iIndex >= nSize))
  940. {
  941. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  942. goto Error;
  943. }
  944. pLogDataInfo = (CLogDataInfo*)m_IndexMgrLogData.GetItemData(iIndex);
  945. if (NULL == pLogDataInfo)
  946. {
  947. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  948. goto Error;
  949. }
  950. //Get the complete record
  951. *pLogData = *pLogDataInfo;
  952. CORg(InternalGetSpecificLog(pLogData));
  953. COM_PROTECT_ERROR_LABEL;
  954. m_csData.Unlock();
  955. return hr;
  956. }
  957. HRESULT
  958. CSpdInfo::GetLogDataInfo(
  959. int iIndex,
  960. CLogDataInfo * pLogData
  961. )
  962. {
  963. HRESULT hr = S_OK;
  964. int nSize = 0;
  965. CLogDataInfo *pLogDataInfo = NULL;
  966. m_csData.Lock();
  967. nSize = (DWORD)m_arrayLogData.GetSize();
  968. if ((iIndex < 0) || (iIndex >= nSize))
  969. {
  970. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  971. goto Error;
  972. }
  973. pLogDataInfo = (CLogDataInfo*)m_IndexMgrLogData.GetItemData(iIndex);
  974. if (NULL == pLogDataInfo)
  975. {
  976. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  977. goto Error;
  978. }
  979. //Get the partial record
  980. *pLogData = *pLogDataInfo;
  981. COM_PROTECT_ERROR_LABEL;
  982. m_csData.Unlock();
  983. return hr;
  984. }
  985. HRESULT
  986. CSpdInfo::SortLogData(
  987. DWORD dwIndexType,
  988. DWORD dwSortOptions
  989. )
  990. {
  991. return m_IndexMgrLogData.SortLogData(dwIndexType, dwSortOptions);
  992. }
  993. HRESULT CSpdInfo::SortLogData()
  994. /*++
  995. CSpdInfo::SortLogData
  996. Description: For use externally, locks and sorts with last set sort
  997. options
  998. Parameters:
  999. Returns:
  1000. --*/
  1001. {
  1002. HRESULT hr = S_OK;
  1003. m_csData.Lock();
  1004. hr = SortLogData(m_dwSortIndex, m_dwSortOption);
  1005. m_csData.Unlock();
  1006. return hr;
  1007. }
  1008. HRESULT
  1009. CSpdInfo::SetSortOptions(
  1010. DWORD dwColID,
  1011. BOOL bAscending
  1012. )
  1013. /*++
  1014. CSpdInfo::SetSortOptions
  1015. Sets the sort options to be used whenever data is enumerated
  1016. --*/
  1017. {
  1018. HRESULT hr = S_OK;
  1019. DWORD dwSortOption = SORT_ASCENDING;
  1020. if( (IDS_COL_LOGDATA_TIME != dwColID) &&
  1021. (IDS_COL_LOGDATA_COMP_ID != dwColID) &&
  1022. (IDS_COL_LOGDATA_CAT != dwColID) &&
  1023. (IDS_COL_LOGDATA_LOCAL_MAC_ADDR != dwColID) &&
  1024. (IDS_COL_LOGDATA_REMOTE_MAC_ADDR != dwColID) &&
  1025. (IDS_COL_LOGDATA_SSID != dwColID) &&
  1026. (IDS_COL_LOGDATA_MSG != dwColID) )
  1027. {
  1028. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1029. goto done;
  1030. }
  1031. if (FALSE == bAscending)
  1032. dwSortOption = SORT_DESCENDING;
  1033. //lock csData so that EnumLogRecords sorts correctly on the next sort
  1034. m_csData.Lock();
  1035. m_dwSortIndex = dwColID;
  1036. m_dwSortOption = dwSortOption;
  1037. m_csData.Unlock();
  1038. done:
  1039. return hr;
  1040. }
  1041. HRESULT
  1042. CSpdInfo::FindIndex(
  1043. int *pnIndex,
  1044. CLogDataInfo *pLogDataInfo
  1045. )
  1046. /*++
  1047. CSpdInfo::FindIndex
  1048. Finds the virtual index of the item corresponding to the input LogDataInfo
  1049. Parameters:
  1050. [out] pnIndex - A pointer to place the result index
  1051. [in] pLogDataInfo - A pointer to the LogDataInfo to be found
  1052. Returns:
  1053. S_OK on success
  1054. *pnIndex will contain a valid index if found, else will have -1
  1055. --*/
  1056. {
  1057. int nSize = 0;
  1058. int i = 0;
  1059. HRESULT hr = S_OK;
  1060. BOOL bFound = FALSE;
  1061. CLogDataInfo *pLogDataLHS = NULL;
  1062. if ( (NULL == pnIndex) || (NULL == pLogDataInfo) )
  1063. {
  1064. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1065. goto Error;
  1066. }
  1067. *pnIndex = -1;
  1068. m_csData.Lock();
  1069. nSize = (int) m_arrayLogData.GetSize();
  1070. while ( (i < nSize) && (FALSE == bFound) )
  1071. {
  1072. pLogDataLHS = (CLogDataInfo*) m_IndexMgrLogData.GetItemData(i);
  1073. if (*pLogDataLHS == *pLogDataInfo)
  1074. {
  1075. *pnIndex = i;
  1076. bFound = TRUE;
  1077. }
  1078. else
  1079. i++;
  1080. }
  1081. m_csData.Unlock();
  1082. COM_PROTECT_ERROR_LABEL;
  1083. return hr;
  1084. }
  1085. HRESULT
  1086. CSpdInfo::GetLastIndex(
  1087. int *pnIndex
  1088. )
  1089. /*++
  1090. CSpdInfo::GetLastIndex
  1091. Returns the virtual index for the last item in the list
  1092. Returns:
  1093. S_OK on success
  1094. --*/
  1095. {
  1096. int nLastIndex = 0;
  1097. HRESULT hr = S_OK;
  1098. if (NULL == pnIndex)
  1099. {
  1100. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1101. goto Error;
  1102. }
  1103. m_csData.Lock();
  1104. nLastIndex = (int) m_arrayLogData.GetSize();
  1105. nLastIndex--;
  1106. *pnIndex = nLastIndex;
  1107. m_csData.Unlock();
  1108. COM_PROTECT_ERROR_LABEL;
  1109. return hr;
  1110. }
  1111. STDMETHODIMP
  1112. CSpdInfo::Destroy()
  1113. {
  1114. //$REVIEW this routine get called when doing auto-refresh
  1115. //We don't need to clean up anything at this time.
  1116. //Each array (Filter, SA, policy...) will get cleaned up when calling the
  1117. //corresponding enum function.
  1118. HANDLE hSession;
  1119. GetSession(&hSession);
  1120. if (m_session_init == true)
  1121. {
  1122. CloseWZCDbLogSession(hSession);
  1123. m_session_init = false;
  1124. m_bFromFirst = TRUE;
  1125. }
  1126. return S_OK;
  1127. }
  1128. DWORD
  1129. CSpdInfo::GetInitInfo()
  1130. {
  1131. CSingleLock cLock(&m_csData);
  1132. cLock.Lock();
  1133. return m_Init;
  1134. }
  1135. void
  1136. CSpdInfo::SetInitInfo(
  1137. DWORD dwInitInfo
  1138. )
  1139. {
  1140. CSingleLock cLock(&m_csData);
  1141. cLock.Lock();
  1142. m_Init=dwInitInfo;
  1143. }
  1144. DWORD
  1145. CSpdInfo::GetActiveInfo()
  1146. {
  1147. CSingleLock cLock(&m_csData);
  1148. cLock.Lock();
  1149. return m_Active;
  1150. }
  1151. void
  1152. CSpdInfo::SetActiveInfo(
  1153. DWORD dwActiveInfo
  1154. )
  1155. {
  1156. CSingleLock cLock(&m_csData);
  1157. cLock.Lock();
  1158. m_Active=dwActiveInfo;
  1159. }
  1160. /*!--------------------------------------------------------------------------
  1161. CreateSpdInfo
  1162. Helper to create the SpdInfo object.
  1163. ---------------------------------------------------------------------------*/
  1164. HRESULT
  1165. CreateSpdInfo(
  1166. ISpdInfo ** ppSpdInfo
  1167. )
  1168. {
  1169. AFX_MANAGE_STATE(AfxGetModuleState());
  1170. SPISpdInfo spSpdInfo;
  1171. ISpdInfo * pSpdInfo = NULL;
  1172. HRESULT hr = hrOK;
  1173. COM_PROTECT_TRY
  1174. {
  1175. pSpdInfo = new CSpdInfo;
  1176. // Do this so that it will get freed on error
  1177. spSpdInfo = pSpdInfo;
  1178. *ppSpdInfo = spSpdInfo.Transfer();
  1179. }
  1180. COM_PROTECT_CATCH
  1181. return hr;
  1182. }
  1183. DWORD
  1184. DeallocateDbRecord(
  1185. PWZC_DB_RECORD const pwzcRec
  1186. )
  1187. /*++
  1188. DeallocateDbRecord - Frees up the internal memory used in a WZC_DB_RECORD
  1189. structure. To be used only when space has been allocated by sources other
  1190. than RPC. Does not deallocate outer level
  1191. Arguments:
  1192. [in/out]pwzcRec - Holds the record to free. Internal mem alone is freed and
  1193. contents freed are annulled.
  1194. Returns:
  1195. ERROR_SUCCESS on success
  1196. --*/
  1197. {
  1198. DWORD dwErr = ERROR_SUCCESS;
  1199. if (NULL != pwzcRec->message.pData)
  1200. {
  1201. delete [] pwzcRec->message.pData;
  1202. pwzcRec->message.pData = NULL;
  1203. }
  1204. if (NULL != pwzcRec->localmac.pData)
  1205. {
  1206. delete [] pwzcRec->localmac.pData;
  1207. pwzcRec->localmac.pData = NULL;
  1208. }
  1209. if (NULL != pwzcRec->remotemac.pData)
  1210. {
  1211. delete [] pwzcRec->remotemac.pData;
  1212. pwzcRec->remotemac.pData = NULL;
  1213. }
  1214. if (NULL != pwzcRec->ssid.pData)
  1215. {
  1216. delete [] pwzcRec->ssid.pData;
  1217. pwzcRec->ssid.pData = NULL;
  1218. }
  1219. if (NULL != pwzcRec->context.pData)
  1220. {
  1221. delete [] pwzcRec->context.pData;
  1222. pwzcRec->ssid.pData = NULL;
  1223. }
  1224. return dwErr;
  1225. }
  1226. //
  1227. // FUNCTIONS: MIDL_user_allocate and MIDL_user_free
  1228. //
  1229. // PURPOSE: Used by stubs to allocate and free memory
  1230. // in standard RPC calls. Not used when
  1231. // [enable_allocate] is specified in the .acf.
  1232. //
  1233. //
  1234. // PARAMETERS:
  1235. // See documentations.
  1236. //
  1237. // RETURN VALUE:
  1238. // Exceptions on error. This is not required,
  1239. // you can use -error allocation on the midl.exe
  1240. // command line instead.
  1241. //
  1242. //
  1243. void * __RPC_USER MIDL_user_allocate(size_t size)
  1244. {
  1245. return(HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size));
  1246. }
  1247. void __RPC_USER MIDL_user_free( void *pointer)
  1248. {
  1249. HeapFree(GetProcessHeap(), 0, pointer);
  1250. }