Source code of Windows XP (NT5)
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.

1292 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: cpdccach.cxx
  7. //
  8. // Contents: PDC Names Cache functionality for the WinNT Provider
  9. //
  10. // Functions:
  11. // CObjNameCache::addentry
  12. // CObjNameCache::findentry
  13. // CObjNameCache::getentry
  14. // CProperyCache::CObjNameCache
  15. // CObjNameCache::~CObjNameCache
  16. // CObjNameCache::CreateClassCache
  17. //
  18. // History: 25-Apr-96 KrishnaG Created.
  19. // 30-Aug-96 RamV Permit cache to store values
  20. // other than PDC names
  21. //
  22. //----------------------------------------------------------------------------
  23. #include "winnt.hxx"
  24. //
  25. // Definition for DsGetDcName on 4.0
  26. //
  27. typedef DWORD (*PF_DsGetDcName) (
  28. IN LPCWSTR ComputerName OPTIONAL,
  29. IN LPCWSTR DomainName OPTIONAL,
  30. IN GUID *DomainGuid OPTIONAL,
  31. IN LPCWSTR SiteName OPTIONAL,
  32. IN ULONG Flags,
  33. OUT PDOMAIN_CONTROLLER_INFO *DomainControllerInfo
  34. );
  35. #ifdef UNICODE
  36. #define GETDCNAME_API "DsGetDcNameW"
  37. #else
  38. #define GETDCNAME_API "DsGetDcNameA"
  39. #endif
  40. //
  41. // DsGetDc will be called if applicabel if not we will look
  42. // at the flags and decide if we should call NetGetAnyDCName or
  43. // NetGetDCName - AjayR 11-04-98.
  44. // Note the code below is not exactly "elegant" but I cannot think
  45. // of any other way to build on 4.0, 95 and NT. Please play close
  46. // attention to the #ifdefs when reading.
  47. //
  48. HRESULT
  49. DsGetDcNameNTWrapper(
  50. IN LPCWSTR DomainName,
  51. OUT LPWSTR *ppszServerName,
  52. IN ULONG Flags
  53. )
  54. {
  55. LPCWSTR ComputerName = NULL;
  56. GUID *DomainGuid = NULL;
  57. LPCWSTR SiteName = NULL;
  58. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  59. DWORD dwStatus = NULL;
  60. LPWSTR pszNetServerName = NULL;
  61. HRESULT hr = S_OK;
  62. ULONG ulDsGetDCFlags = DS_RETURN_FLAT_NAME | DS_WRITABLE_REQUIRED;
  63. if (Flags & ADS_READONLY_SERVER) {
  64. ulDsGetDCFlags &= ~DS_WRITABLE_REQUIRED;
  65. }
  66. *ppszServerName = NULL;
  67. static PF_DsGetDcName pfDsGetDcName = NULL ;
  68. //
  69. // Load the function if necessary
  70. //
  71. if (pfDsGetDcName == NULL) {
  72. pfDsGetDcName =
  73. (PF_DsGetDcName) LoadNetApi32Function(GETDCNAME_API) ;
  74. }
  75. if (pfDsGetDcName != NULL) {
  76. dwStatus = ((*pfDsGetDcName)(
  77. ComputerName,
  78. DomainName,
  79. DomainGuid,
  80. SiteName,
  81. ulDsGetDCFlags,
  82. &pDomainControllerInfo
  83. )
  84. );
  85. if (dwStatus == NO_ERROR) {
  86. *ppszServerName = AllocADsStr(
  87. pDomainControllerInfo->DomainControllerName
  88. );
  89. if (!*ppszServerName)
  90. hr = E_OUTOFMEMORY;
  91. } else {
  92. hr = HRESULT_FROM_WIN32(dwStatus);
  93. }
  94. } else {
  95. //
  96. // Could not load library
  97. //
  98. if (Flags & ADS_READONLY_SERVER) {
  99. #ifdef WIN95
  100. dwStatus = NetGetDCName(
  101. NULL,
  102. DomainName,
  103. (LPBYTE *)&pszNetServerName
  104. );
  105. #else
  106. dwStatus = NetGetAnyDCName(
  107. NULL,
  108. DomainName,
  109. (LPBYTE *)&pszNetServerName
  110. );
  111. #endif
  112. } else {
  113. dwStatus = NetGetDCName(
  114. NULL,
  115. DomainName,
  116. (LPBYTE *)&pszNetServerName
  117. );
  118. }
  119. if (dwStatus == NO_ERROR) {
  120. *ppszServerName = AllocADsStr(
  121. pszNetServerName
  122. );
  123. if (!*ppszServerName)
  124. hr = E_OUTOFMEMORY;
  125. } else {
  126. hr = HRESULT_FROM_WIN32(dwStatus);
  127. }
  128. }
  129. if (pszNetServerName) {
  130. (void) NetApiBufferFree( (void*) pszNetServerName);
  131. }
  132. if (pDomainControllerInfo) {
  133. (void) NetApiBufferFree(pDomainControllerInfo);
  134. }
  135. RRETURN(hr);
  136. }
  137. //+------------------------------------------------------------------------
  138. //
  139. // Function: CObjNameCache::addentry
  140. //
  141. // Synopsis:
  142. //
  143. //
  144. //
  145. // Arguments: [pszDomainName] --
  146. // [pszPDCName] --
  147. // [pClassEntry] --
  148. //
  149. //
  150. //-------------------------------------------------------------------------
  151. HRESULT
  152. CObjNameCache::
  153. addentry(
  154. LPWSTR pszElementName,
  155. BOOL fCacheHit,
  156. DWORD dwElementType,
  157. LPWSTR pszName
  158. )
  159. {
  160. //
  161. // The parameter pszName is either the Domain/Wkgrp Name (if dwElementType
  162. // = COMPUTER_ENTRY_TYPE) and PDC Name (if dwElementType is
  163. // DOMAIN_ENTRY_TYPE). it will be a blank string if dwElementType is
  164. // WORKGROUP_ENTRY_TYPE
  165. //
  166. // we will support adding cache hits/misses.
  167. //
  168. HRESULT hr = S_OK;
  169. DWORD i = 0;
  170. DWORD dwLRUEntry = 0;
  171. DWORD dwIndex = 0;
  172. EnterCriticalSection(&_cs);
  173. //
  174. // before adding entries, let us clean out all existing old entries
  175. //
  176. if (_dwMaxCacheSize == 0){
  177. hr = E_FAIL;
  178. goto error;
  179. }
  180. hr = InvalidateStaleEntries();
  181. BAIL_ON_FAILURE(hr);
  182. hr = findentry(
  183. pszElementName,
  184. &dwIndex
  185. );
  186. //
  187. // if you find an entry then you cannot add it to the cache
  188. //
  189. if(SUCCEEDED(hr)){
  190. goto error;
  191. }
  192. hr = S_OK;
  193. for (i = 0; i < _dwMaxCacheSize; i++ ) {
  194. if (!_ClassEntries[i].bInUse) {
  195. //
  196. // Found an available entry; use it
  197. // fill in the name of the entry and related information
  198. // for this class entry
  199. //
  200. break;
  201. } else {
  202. if ((dwLRUEntry == -1) || (i == IsOlderThan(i, dwLRUEntry))){
  203. dwLRUEntry = i;
  204. }
  205. }
  206. }
  207. if (i == _dwMaxCacheSize){
  208. //
  209. // We have no available entries so we need to use
  210. // the LRUEntry which is busy
  211. //
  212. //
  213. // Free this entry
  214. //
  215. _ClassEntries[dwLRUEntry].bInUse = FALSE;
  216. i = dwLRUEntry;
  217. }
  218. //
  219. // Insert the new entry into the Cache
  220. //
  221. _ClassEntries[i].pszElementName = AllocADsStr(pszElementName);
  222. if(_ClassEntries[i].pszElementName == NULL){
  223. hr = E_OUTOFMEMORY;
  224. goto error;
  225. }
  226. _ClassEntries[i].dwElementType = dwElementType;
  227. if ( fCacheHit){
  228. _ClassEntries[i].fCacheHit = TRUE;
  229. switch(dwElementType) {
  230. case DOMAIN_ENTRY_TYPE:
  231. _ClassEntries[i].u.pszPDCName = AllocADsStr(pszName);
  232. if(_ClassEntries[i].u.pszPDCName == NULL){
  233. hr = E_OUTOFMEMORY;
  234. goto error;
  235. }
  236. break;
  237. case DOMAIN_ENTRY_TYPE_RO:
  238. _ClassEntries[i].u.pszDCName = AllocADsStr(pszName);
  239. if (_ClassEntries[i].u.pszDCName == NULL) {
  240. hr = E_OUTOFMEMORY;
  241. goto error;
  242. }
  243. break;
  244. case COMPUTER_ENTRY_TYPE:
  245. _ClassEntries[i].u.pszDomainName = AllocADsStr(pszName);
  246. if(_ClassEntries[i].u.pszDomainName == NULL){
  247. hr = E_OUTOFMEMORY;
  248. goto error;
  249. }
  250. break;
  251. default:
  252. break;
  253. }
  254. } else {
  255. _ClassEntries[i].fCacheHit = FALSE;
  256. }
  257. _ClassEntries[i].bInUse = TRUE;
  258. //
  259. // update the time stamp so that we know when this entry was made
  260. //
  261. GetSystemTime(&_ClassEntries[i].st);
  262. error:
  263. LeaveCriticalSection(&_cs);
  264. RRETURN(hr);
  265. }
  266. //+------------------------------------------------------------------------
  267. //
  268. // Function: CObjNameCache::findentry
  269. //
  270. // Synopsis:
  271. //
  272. //
  273. //
  274. // Arguments: [szPropertyName] --
  275. // [pdwIndex] --
  276. //
  277. //-------------------------------------------------------------------------
  278. HRESULT
  279. CObjNameCache::
  280. findentry(
  281. LPWSTR pszElementName,
  282. PDWORD pdwIndex
  283. )
  284. {
  285. DWORD i = 0;
  286. EnterCriticalSection(&_cs);
  287. if (_dwMaxCacheSize == 0 ) {
  288. LeaveCriticalSection(&_cs);
  289. RRETURN(E_FAIL);
  290. }
  291. for (i = 0; i < _dwMaxCacheSize; i++ ) {
  292. if (_ClassEntries[i].bInUse) {
  293. if(!_ClassEntries[i].pszElementName ){
  294. continue;
  295. }
  296. #ifdef WIN95
  297. if (!_wcsicmp(_ClassEntries[i].pszElementName, pszElementName)){
  298. #else
  299. if (CompareStringW(
  300. LOCALE_SYSTEM_DEFAULT,
  301. NORM_IGNORECASE,
  302. _ClassEntries[i].pszElementName,
  303. -1,
  304. pszElementName,
  305. -1
  306. ) == CSTR_EQUAL ) {
  307. #endif
  308. *pdwIndex = i;
  309. LeaveCriticalSection(&_cs);
  310. RRETURN(S_OK);
  311. }
  312. }
  313. }
  314. LeaveCriticalSection(&_cs);
  315. RRETURN(E_FAIL);
  316. }
  317. //+------------------------------------------------------------------------
  318. //
  319. // Function: CObjNameCache::getentry
  320. //
  321. // Synopsis:
  322. //
  323. //
  324. //
  325. // Arguments: [szPropertyName] --
  326. // [pdwIndex] --
  327. //
  328. //-------------------------------------------------------------------------
  329. HRESULT
  330. CObjNameCache::
  331. getentry(
  332. LPWSTR pszElementName,
  333. PBOOL pfHit,
  334. PDWORD pdwEntryType,
  335. LPWSTR pszName
  336. )
  337. {
  338. DWORD dwIndex = 0;
  339. HRESULT hr = S_OK;
  340. DWORD i;
  341. EnterCriticalSection(&_cs);
  342. //
  343. // blow away all the entries that have expired
  344. //
  345. hr = InvalidateStaleEntries();
  346. BAIL_ON_FAILURE(hr);
  347. hr = findentry(
  348. pszElementName,
  349. &dwIndex
  350. );
  351. BAIL_ON_FAILURE(hr);
  352. *pfHit = _ClassEntries[dwIndex].fCacheHit;
  353. *pdwEntryType = _ClassEntries[dwIndex].dwElementType;
  354. switch(_ClassEntries[dwIndex].dwElementType) {
  355. case DOMAIN_ENTRY_TYPE:
  356. wcscpy(pszName, _ClassEntries[dwIndex].u.pszPDCName);
  357. break;
  358. case COMPUTER_ENTRY_TYPE:
  359. wcscpy(pszName, _ClassEntries[dwIndex].u.pszDomainName);
  360. break;
  361. case DOMAIN_ENTRY_TYPE_RO:
  362. wcscpy(pszName, _ClassEntries[dwIndex].u.pszDCName);
  363. break;
  364. default:
  365. wcscpy(pszName, TEXT(""));
  366. break;
  367. }
  368. error:
  369. LeaveCriticalSection(&_cs);
  370. RRETURN(hr);
  371. }
  372. HRESULT
  373. CObjNameCache::
  374. InvalidateStaleEntries()
  375. {
  376. DWORD i=0;
  377. SYSTEMTIME stCurrentTime;
  378. BOOL fCacheHit;
  379. GetSystemTime(&stCurrentTime);
  380. for ( i=0; i< _dwMaxCacheSize; i++){
  381. fCacheHit = _ClassEntries[i].fCacheHit;
  382. if(_ClassEntries[i].bInUse &&
  383. TimeDifference(stCurrentTime, _ClassEntries[i].st)
  384. > AGE_LIMIT_VALID_ENTRIES && fCacheHit == CACHE_HIT) {
  385. _ClassEntries[i].bInUse = FALSE;
  386. FreeADsStr(_ClassEntries[i].pszElementName);
  387. _ClassEntries[i].pszElementName = NULL;
  388. if(_ClassEntries[i].dwElementType == DOMAIN_ENTRY_TYPE){
  389. FreeADsStr(_ClassEntries[i].u.pszPDCName);
  390. _ClassEntries[i].u.pszPDCName = NULL;
  391. } else if (_ClassEntries[i].dwElementType == COMPUTER_ENTRY_TYPE){
  392. FreeADsStr(_ClassEntries[i].u.pszDomainName);
  393. _ClassEntries[i].u.pszPDCName = NULL;
  394. }
  395. }else if(_ClassEntries[i].bInUse &&
  396. TimeDifference(stCurrentTime, _ClassEntries[i].st)
  397. > AGE_LIMIT_INVALID_ENTRIES && fCacheHit == CACHE_MISS) {
  398. _ClassEntries[i].bInUse = FALSE;
  399. }
  400. }
  401. RRETURN(S_OK);
  402. }
  403. //+------------------------------------------------------------------------
  404. //
  405. // Function: CObjNameCache
  406. //
  407. // Synopsis:
  408. //
  409. //
  410. //
  411. // Arguments:
  412. //
  413. //
  414. //-------------------------------------------------------------------------
  415. CObjNameCache::CObjNameCache()
  416. {
  417. _dwMaxCacheSize = 10;
  418. memset(_ClassEntries, 0, sizeof(CLASSENTRY)* MAX_ENTRIES);
  419. }
  420. //+------------------------------------------------------------------------
  421. //
  422. // Function: ~CObjNameCache
  423. //
  424. // Synopsis:
  425. //
  426. //
  427. //
  428. // Arguments:
  429. //
  430. //
  431. //-------------------------------------------------------------------------
  432. CObjNameCache::
  433. ~CObjNameCache()
  434. {
  435. DWORD i= 0;
  436. for (i=0; i< MAX_ENTRIES; i++){
  437. if(_ClassEntries[i].pszElementName){
  438. FreeADsStr(_ClassEntries[i].pszElementName);
  439. }
  440. //
  441. // All members of the union are strings so it is not
  442. // necessary to check for each of the members.
  443. //
  444. if(_ClassEntries[i].u.pszPDCName){
  445. FreeADsStr(_ClassEntries[i].u.pszPDCName);
  446. }
  447. }
  448. DeleteCriticalSection(&_cs);
  449. }
  450. //+------------------------------------------------------------------------
  451. //
  452. // Function:
  453. //
  454. // Synopsis:
  455. //
  456. //
  457. //
  458. // Arguments:
  459. //
  460. //
  461. //-------------------------------------------------------------------------
  462. HRESULT
  463. CObjNameCache::
  464. CreateClassCache(
  465. CObjNameCache FAR *FAR * ppClassCache
  466. )
  467. {
  468. CObjNameCache FAR * pClassCache = NULL;
  469. pClassCache = new CObjNameCache();
  470. if (!pClassCache) {
  471. RRETURN(E_FAIL);
  472. }
  473. InitializeCriticalSection(&(pClassCache->_cs));
  474. *ppClassCache = pClassCache;
  475. RRETURN(S_OK);
  476. }
  477. DWORD
  478. CObjNameCache::
  479. IsOlderThan(
  480. DWORD i,
  481. DWORD j
  482. )
  483. {
  484. SYSTEMTIME *pi, *pj;
  485. DWORD iMs, jMs;
  486. // DBGMSG(DBG_TRACE, ("IsOlderThan entering with i %d j %d\n", i, j));
  487. pi = &(_ClassEntries[i].st);
  488. pj = &(_ClassEntries[j].st);
  489. if (pi->wYear < pj->wYear) {
  490. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  491. return(i);
  492. } else if (pi->wYear > pj->wYear) {
  493. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  494. return(j);
  495. } else if (pi->wMonth < pj->wMonth) {
  496. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  497. return(i);
  498. } else if (pi->wMonth > pj->wMonth) {
  499. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  500. return(j);
  501. } else if (pi->wDay < pj->wDay) {
  502. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  503. return(i);
  504. } else if (pi->wDay > pj->wDay) {
  505. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  506. return(j);
  507. } else {
  508. iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
  509. jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
  510. if (iMs <= jMs) {
  511. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  512. return(i);
  513. } else {
  514. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  515. return(j);
  516. }
  517. }
  518. }
  519. HRESULT
  520. WinNTGetCachedDCName(
  521. LPWSTR pszDomainName,
  522. LPWSTR pszPDCName,
  523. DWORD dwFlags
  524. )
  525. {
  526. WCHAR szSAMName[MAX_PATH];
  527. // In this case credentials do not help because we do not have
  528. // any server/domain to connect to. This is because the param
  529. // pszDomainName is not a domain name for certain.
  530. CWinNTCredentials nullCredentials;
  531. // We do want to copy the flags parameter as that will tell
  532. // us if we need to connect to PDC or not
  533. nullCredentials.SetFlags(dwFlags);
  534. RRETURN(WinNTGetCachedObject(pszDomainName,
  535. DOMAIN_ENTRY_TYPE,
  536. pszPDCName,
  537. szSAMName,
  538. dwFlags,
  539. nullCredentials
  540. ));
  541. }
  542. HRESULT
  543. WinNTGetCachedComputerName(
  544. LPWSTR pszComputerName,
  545. LPWSTR pszName,
  546. LPWSTR pszSAMName,
  547. CWinNTCredentials& Credentials
  548. )
  549. {
  550. RRETURN(WinNTGetCachedObject(pszComputerName,
  551. COMPUTER_ENTRY_TYPE,
  552. pszName,
  553. pszSAMName,
  554. Credentials.GetFlags(), // doesnt matter
  555. Credentials
  556. ));
  557. }
  558. HRESULT
  559. WinNTGetCachedObject(
  560. LPWSTR pszElementName,
  561. DWORD dwElementType,
  562. LPWSTR pszName,
  563. LPWSTR pszSAMName,
  564. DWORD dwFlags,
  565. CWinNTCredentials& Credentials
  566. )
  567. {
  568. HRESULT hr = S_OK;
  569. NET_API_STATUS nasStatus = 0;
  570. BOOL fCacheHit;
  571. DWORD dwEntryType;
  572. LPWKSTA_INFO_100 lpWI = NULL;
  573. DWORD dwObjectsReturned;
  574. DWORD dwObjectsTotal;
  575. DWORD dwResumeHandle;
  576. // Freed using NetAPI
  577. LPWSTR pszServerName = NULL;
  578. // Freed using FreeADsStr
  579. LPWSTR pszADsStrServerName = NULL;
  580. BOOL fRefAdded = FALSE;
  581. DWORD dwDomainEntryType = DOMAIN_ENTRY_TYPE;
  582. // This will be the case most often
  583. DWORD dwUserFlags = Credentials.GetFlags();
  584. DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomainInfo = NULL;
  585. hr = pgPDCNameCache->getentry(
  586. pszElementName,
  587. &fCacheHit,
  588. &dwEntryType,
  589. pszName
  590. );
  591. if (SUCCEEDED(hr)) {
  592. //
  593. // we found the entry. Now need to verify that it indeed
  594. // is an object of type desired
  595. //
  596. // Note that dwElement type will never be DOMAIN_ENTRY_TYPE_RO
  597. if(fCacheHit) {
  598. if (dwEntryType == dwElementType
  599. || ((dwElementType == DOMAIN_ENTRY_TYPE)
  600. && (dwEntryType == DOMAIN_ENTRY_TYPE_RO)
  601. && (dwUserFlags & ADS_READONLY_SERVER))
  602. ) {
  603. //
  604. // If the user now needs a writeable connection
  605. // should we fail or should we actually pretend
  606. // that the object is not there in the cache.
  607. //
  608. hr = S_OK;
  609. goto error;
  610. }
  611. } else if (!fCacheHit && (dwElementType == WORKGROUP_ENTRY_TYPE)) {
  612. //
  613. // looks like we either found a cache miss
  614. // Return ok
  615. //
  616. hr = S_OK;
  617. goto error;
  618. } else {
  619. hr = E_FAIL;
  620. goto error;
  621. }
  622. }
  623. switch(dwElementType){
  624. case DOMAIN_ENTRY_TYPE:
  625. //
  626. // A read only server is ok, need to also set the
  627. // domain entry type accordingly
  628. //
  629. if (dwFlags & ADS_READONLY_SERVER) {
  630. dwDomainEntryType = DOMAIN_ENTRY_TYPE_RO;
  631. }
  632. //
  633. // Call the all encompassing Wrapper.
  634. //
  635. hr = DsGetDcNameNTWrapper(
  636. pszElementName,
  637. &pszADsStrServerName,
  638. dwFlags
  639. );
  640. BAIL_ON_FAILURE(hr);
  641. hr = pgPDCNameCache->addentry(
  642. pszElementName,
  643. TRUE,
  644. dwDomainEntryType,
  645. pszADsStrServerName
  646. );
  647. BAIL_ON_FAILURE(hr);
  648. //
  649. // in addition we can also add a computer entry for the PDC
  650. //
  651. hr = pgPDCNameCache->addentry(
  652. pszADsStrServerName+2, // to get rid of the leading backslashes
  653. TRUE,
  654. COMPUTER_ENTRY_TYPE,
  655. pszElementName
  656. );
  657. BAIL_ON_FAILURE(hr);
  658. wcscpy(pszName, pszADsStrServerName);
  659. break;
  660. case COMPUTER_ENTRY_TYPE:
  661. // Ref the computer, note that RefServer will not
  662. // do anything if the credentials are null. We are also
  663. // not worried about errors as we want to use default
  664. // credentials in that case.
  665. hr = Credentials.RefServer(pszElementName);
  666. if (SUCCEEDED(hr)) {
  667. fRefAdded = TRUE;
  668. }
  669. nasStatus = NetWkstaGetInfo(
  670. pszElementName,
  671. 100,
  672. (LPBYTE*) &lpWI
  673. );
  674. hr = HRESULT_FROM_WIN32(nasStatus);
  675. BAIL_ON_FAILURE(hr);
  676. #ifdef WIN95
  677. //
  678. // No NetpNameCompare for Win9x
  679. //
  680. if (lpWI->wki100_computername
  681. && (_wcsicmp(pszElementName, lpWI->wki100_computername) == 0)
  682. )
  683. #else
  684. if (lpWI->wki100_computername
  685. && ( NetpNameCompare(
  686. NULL,
  687. pszElementName,
  688. lpWI->wki100_computername,
  689. NAMETYPE_COMPUTER,
  690. 0
  691. )
  692. == 0 )
  693. )
  694. #endif
  695. {
  696. // Want to add the correct capitalized name
  697. // Not what the user gave
  698. hr = pgPDCNameCache->addentry(
  699. lpWI->wki100_computername,
  700. TRUE,
  701. COMPUTER_ENTRY_TYPE,
  702. lpWI->wki100_langroup
  703. );
  704. wcscpy(pszSAMName, lpWI->wki100_computername);
  705. }
  706. else {
  707. //
  708. // user actually passes in ipaddress as the computer name
  709. //
  710. if(IsAddressNumeric(pszElementName)) {
  711. hr = pgPDCNameCache->addentry(
  712. pszElementName,
  713. TRUE,
  714. COMPUTER_ENTRY_TYPE,
  715. lpWI->wki100_langroup
  716. );
  717. wcscpy(pszSAMName, L"");
  718. }
  719. //
  720. // user may pass in the dns name of the computer
  721. //
  722. else {
  723. hr = HRESULT_FROM_WIN32(DsRoleGetPrimaryDomainInformation(
  724. pszElementName,
  725. DsRolePrimaryDomainInfoBasic, // InfoLevel
  726. (PBYTE*)&pdomainInfo // pBuffer
  727. ));
  728. if(SUCCEEDED(hr)) {
  729. if(((pdomainInfo->DomainNameDns) && _wcsicmp(pszElementName, pdomainInfo->DomainNameDns) == 0)
  730. ||
  731. ((pdomainInfo->DomainNameFlat) && NetpNameCompare(
  732. NULL,
  733. pszElementName,
  734. pdomainInfo->DomainNameFlat,
  735. NAMETYPE_COMPUTER,
  736. 0
  737. )
  738. == 0) )
  739. {
  740. BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
  741. }
  742. else {
  743. hr = pgPDCNameCache->addentry(
  744. pszElementName,
  745. TRUE,
  746. COMPUTER_ENTRY_TYPE,
  747. lpWI->wki100_langroup
  748. );
  749. wcscpy(pszSAMName, L"");
  750. }
  751. }
  752. else {
  753. BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
  754. }
  755. }
  756. }
  757. wcscpy(pszName, lpWI->wki100_langroup);
  758. break;
  759. default:
  760. hr = E_FAIL;
  761. break;
  762. }
  763. error:
  764. if (fRefAdded) {
  765. Credentials.DeRefServer();
  766. // even if we fail, we have no recovery path
  767. fRefAdded = FALSE;
  768. }
  769. if(lpWI){
  770. NetApiBufferFree(lpWI);
  771. }
  772. if(pszServerName){
  773. NetApiBufferFree(pszServerName);
  774. }
  775. if (pszADsStrServerName) {
  776. FreeADsStr(pszADsStrServerName);
  777. }
  778. if ( pdomainInfo )
  779. {
  780. DsRoleFreeMemory(pdomainInfo);
  781. }
  782. RRETURN(hr);
  783. }
  784. //+------------------------------------------------------------------------
  785. //
  786. // Function:
  787. //
  788. // Synopsis:
  789. // This function is called by Heuristic GetObject to identify what
  790. // kind of object we are dealing with. Here we try to get a cached
  791. // entry if it is a hit/miss. If it fails, then we try each kind
  792. // of object in turn. (Domain/Computer/Workgroup). Once we do this,
  793. // we cache this information internally
  794. //
  795. //
  796. //
  797. // Arguments:
  798. //
  799. //
  800. //-------------------------------------------------------------------------
  801. HRESULT
  802. WinNTGetCachedName(
  803. LPWSTR pszElementName,
  804. PDWORD pdwElementType,
  805. LPWSTR pszName,
  806. LPWSTR pszSAMName,
  807. CWinNTCredentials& Credentials
  808. )
  809. {
  810. HRESULT hr = S_OK;
  811. BOOL fCacheHit;
  812. DWORD dwEntryType;
  813. WCHAR szSAMName[MAX_ADS_PATH];
  814. BOOL fRefAdded = FALSE;
  815. DWORD dwUserFlags = Credentials.GetFlags();
  816. szSAMName[0] = L'\0';
  817. if (!pszElementName || !*pszElementName) {
  818. RRETURN(E_FAIL);
  819. }
  820. hr = pgPDCNameCache->getentry(
  821. pszElementName,
  822. &fCacheHit,
  823. &dwEntryType,
  824. pszName
  825. );
  826. if (SUCCEEDED(hr)) {
  827. //
  828. // we found the entry.
  829. //
  830. if (!fCacheHit){
  831. //
  832. // cache miss saved as a workgroup
  833. //
  834. *pdwElementType = WORKGROUP_ENTRY_TYPE;
  835. goto error;
  836. } else {
  837. if(dwEntryType == DOMAIN_ENTRY_TYPE_RO) {
  838. if(dwUserFlags & ADS_READONLY_SERVER) {
  839. // HeuristicGetObj doesn't recognize DOMAIN_ENTRY_TYPE_RO
  840. *pdwElementType = DOMAIN_ENTRY_TYPE;
  841. goto error;
  842. }
  843. }
  844. else {
  845. *pdwElementType = dwEntryType;
  846. goto error;
  847. }
  848. }
  849. }
  850. {
  851. // at this point, we can try and ref the domain as
  852. // we are looking to bind to the domain
  853. hr = Credentials.RefDomain(pszElementName);
  854. // note that even if this fails we want to continue
  855. // as there is the chance that the current users
  856. // credentials are good enough for the operation
  857. if (SUCCEEDED(hr)) {
  858. fRefAdded = TRUE;
  859. }
  860. hr = WinNTGetCachedObject(
  861. pszElementName,
  862. DOMAIN_ENTRY_TYPE,
  863. pszName,
  864. szSAMName,
  865. Credentials.GetFlags(),
  866. Credentials
  867. );
  868. if (fRefAdded) {
  869. Credentials.DeRefDomain();
  870. // we cannot really do anything useful with HR
  871. fRefAdded = FALSE;
  872. }
  873. if (SUCCEEDED(hr)){
  874. *pdwElementType = DOMAIN_ENTRY_TYPE;
  875. wcscpy(pszSAMName, szSAMName);
  876. RRETURN(hr);
  877. }
  878. hr = WinNTGetCachedObject(
  879. pszElementName,
  880. COMPUTER_ENTRY_TYPE,
  881. pszName,
  882. szSAMName,
  883. Credentials.GetFlags(),
  884. Credentials
  885. );
  886. if (SUCCEEDED(hr)){
  887. *pdwElementType = COMPUTER_ENTRY_TYPE;
  888. wcscpy(pszSAMName, szSAMName);
  889. RRETURN(hr);
  890. }
  891. //
  892. // if you are here, it means that you have to cache a miss as a
  893. // workgroup.
  894. // Note that pszSAMName rather than pszElementName is added
  895. // if it is valid
  896. // AjayR - to handle the no workstation case,
  897. // We should not add anything if the error was NOWksta service
  898. if (hr != HRESULT_FROM_WIN32(NERR_WkstaNotStarted)) {
  899. if (szSAMName[0] != L'\0') {
  900. hr = pgPDCNameCache->addentry(
  901. szSAMName,
  902. FALSE,
  903. WORKGROUP_ENTRY_TYPE,
  904. TEXT("")
  905. );
  906. } else {
  907. hr = pgPDCNameCache->addentry(
  908. pszElementName,
  909. FALSE,
  910. WORKGROUP_ENTRY_TYPE,
  911. TEXT("")
  912. );
  913. }
  914. } // No Wksta started
  915. *pdwElementType = WORKGROUP_ENTRY_TYPE;
  916. wcscpy(pszName, TEXT(""));
  917. goto error;
  918. }
  919. error:
  920. RRETURN(hr);
  921. }
  922. LONG
  923. TimeDifference(
  924. SYSTEMTIME st1,
  925. SYSTEMTIME st2
  926. )
  927. {
  928. //
  929. // This function gives the difference between st1 and st2 (st1-st2)in secs.
  930. // This will be used by our internal cache object so as to find out if
  931. // a certain entry in the cache is too old.
  932. // Assumption: st1 is later than st2.
  933. DWORD dwTime1;
  934. DWORD dwTime2;
  935. DWORD dwMonth1;
  936. DWORD dwMonth2;
  937. LONG lRetval;
  938. //
  939. // Ignore milliseconds because it is immaterial for our purposes
  940. //
  941. dwTime1= st1.wSecond + 60 *
  942. (st1.wMinute + 60* (st1.wHour + 24 * (st1.wDay)));
  943. dwTime2= st2.wSecond + 60 *
  944. (st2.wMinute + 60* (st2.wHour + 24 * (st2.wDay)));
  945. if (dwTime1 == dwTime2) {
  946. return(0);
  947. }
  948. if (dwTime1 > dwTime2 && (st1.wMonth == st2.wMonth) &&
  949. st1.wYear == st2.wYear) {
  950. lRetval = (LONG)(dwTime1-dwTime2);
  951. goto cleanup;
  952. }
  953. dwMonth1 = 12*st1.wYear+ st1.wMonth;
  954. dwMonth2 = 12*st2.wYear+ st2.wMonth;
  955. if (dwMonth1 < dwMonth2) {
  956. //
  957. // looks like we got a bogus value. return -1
  958. //
  959. lRetval = -1;
  960. goto cleanup;
  961. }
  962. //
  963. // if there is a month difference of more than 1 then we return
  964. // a large positive number (0xFFFFFFF)
  965. //
  966. if (dwMonth1 > dwMonth2+1) {
  967. lRetval = 0xFFFFFFF;
  968. goto cleanup;
  969. }
  970. //
  971. // we crossed a month boundary
  972. //
  973. dwTime1= st1.wSecond + 60 *
  974. (st1.wMinute + 60* (st1.wHour));
  975. dwTime2= st2.wSecond + 60 *
  976. (st2.wMinute);
  977. lRetval = ( dwTime2- dwTime1 + 60*60*24);
  978. goto cleanup;
  979. cleanup:
  980. return(lRetval);
  981. }
  982. BOOL
  983. IsAddressNumeric(
  984. LPWSTR HostName
  985. )
  986. {
  987. BOOLEAN rc = FALSE;
  988. //
  989. // to check to see if it's a TCP address, we check for it to only
  990. // contain only numerals and periods.
  991. //
  992. while (((*HostName >= L'0') && (*HostName <= L'9')) ||
  993. (*HostName == L'.')) {
  994. HostName++;
  995. }
  996. //
  997. // if we hit the end of the hostname, then it's an address.
  998. //
  999. if (*HostName == L'\0' || *HostName == L':') {
  1000. rc = TRUE;
  1001. }
  1002. return rc;
  1003. }