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.

1383 lines
34 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 the members of the LRU Entry
  214. //
  215. if (_ClassEntries[dwLRUEntry].pszElementName)
  216. {
  217. FreeADsStr(_ClassEntries[dwLRUEntry].pszElementName);
  218. _ClassEntries[dwLRUEntry].pszElementName = NULL;
  219. }
  220. //
  221. // All members of the union are strings so it is not
  222. // necessary to check for each of the members. Just free
  223. // one of them if it is non-null.
  224. //
  225. if(_ClassEntries[i].u.pszPDCName)
  226. {
  227. FreeADsStr(_ClassEntries[i].u.pszPDCName);
  228. _ClassEntries[i].u.pszPDCName = NULL;
  229. }
  230. _ClassEntries[dwLRUEntry].bInUse = FALSE;
  231. i = dwLRUEntry;
  232. }
  233. //
  234. // Insert the new entry into the Cache
  235. //
  236. _ClassEntries[i].pszElementName = AllocADsStr(pszElementName);
  237. if(_ClassEntries[i].pszElementName == NULL){
  238. hr = E_OUTOFMEMORY;
  239. goto error;
  240. }
  241. _ClassEntries[i].dwElementType = dwElementType;
  242. if ( fCacheHit){
  243. _ClassEntries[i].fCacheHit = TRUE;
  244. switch(dwElementType) {
  245. case DOMAIN_ENTRY_TYPE:
  246. _ClassEntries[i].u.pszPDCName = AllocADsStr(pszName);
  247. if(_ClassEntries[i].u.pszPDCName == NULL){
  248. hr = E_OUTOFMEMORY;
  249. goto error;
  250. }
  251. break;
  252. case DOMAIN_ENTRY_TYPE_RO:
  253. _ClassEntries[i].u.pszDCName = AllocADsStr(pszName);
  254. if (_ClassEntries[i].u.pszDCName == NULL) {
  255. hr = E_OUTOFMEMORY;
  256. goto error;
  257. }
  258. break;
  259. case COMPUTER_ENTRY_TYPE:
  260. _ClassEntries[i].u.pszDomainName = AllocADsStr(pszName);
  261. if(_ClassEntries[i].u.pszDomainName == NULL){
  262. hr = E_OUTOFMEMORY;
  263. goto error;
  264. }
  265. break;
  266. default:
  267. break;
  268. }
  269. } else {
  270. _ClassEntries[i].fCacheHit = FALSE;
  271. }
  272. _ClassEntries[i].bInUse = TRUE;
  273. //
  274. // update the time stamp so that we know when this entry was made
  275. //
  276. GetSystemTime(&_ClassEntries[i].st);
  277. error:
  278. LeaveCriticalSection(&_cs);
  279. RRETURN(hr);
  280. }
  281. //+------------------------------------------------------------------------
  282. //
  283. // Function: CObjNameCache::findentry
  284. //
  285. // Synopsis:
  286. //
  287. //
  288. //
  289. // Arguments: [szPropertyName] --
  290. // [pdwIndex] --
  291. //
  292. //-------------------------------------------------------------------------
  293. HRESULT
  294. CObjNameCache::
  295. findentry(
  296. LPWSTR pszElementName,
  297. PDWORD pdwIndex
  298. )
  299. {
  300. DWORD i = 0;
  301. EnterCriticalSection(&_cs);
  302. if (_dwMaxCacheSize == 0 ) {
  303. LeaveCriticalSection(&_cs);
  304. RRETURN(E_FAIL);
  305. }
  306. for (i = 0; i < _dwMaxCacheSize; i++ ) {
  307. if (_ClassEntries[i].bInUse) {
  308. if(!_ClassEntries[i].pszElementName ){
  309. continue;
  310. }
  311. #ifdef WIN95
  312. if (!_wcsicmp(_ClassEntries[i].pszElementName, pszElementName)){
  313. #else
  314. if (CompareStringW(
  315. LOCALE_SYSTEM_DEFAULT,
  316. NORM_IGNORECASE,
  317. _ClassEntries[i].pszElementName,
  318. -1,
  319. pszElementName,
  320. -1
  321. ) == CSTR_EQUAL ) {
  322. #endif
  323. *pdwIndex = i;
  324. LeaveCriticalSection(&_cs);
  325. RRETURN(S_OK);
  326. }
  327. }
  328. }
  329. LeaveCriticalSection(&_cs);
  330. RRETURN(E_FAIL);
  331. }
  332. //+------------------------------------------------------------------------
  333. //
  334. // Function: CObjNameCache::getentry
  335. //
  336. // Synopsis:
  337. //
  338. //
  339. //
  340. // Arguments: [szPropertyName] --
  341. // [pdwIndex] --
  342. //
  343. //-------------------------------------------------------------------------
  344. HRESULT
  345. CObjNameCache::
  346. getentry(
  347. LPWSTR pszElementName,
  348. PBOOL pfHit,
  349. PDWORD pdwEntryType,
  350. LPWSTR pszName
  351. )
  352. {
  353. DWORD dwIndex = 0;
  354. HRESULT hr = S_OK;
  355. DWORD i;
  356. EnterCriticalSection(&_cs);
  357. //
  358. // blow away all the entries that have expired
  359. //
  360. hr = InvalidateStaleEntries();
  361. BAIL_ON_FAILURE(hr);
  362. hr = findentry(
  363. pszElementName,
  364. &dwIndex
  365. );
  366. BAIL_ON_FAILURE(hr);
  367. *pfHit = _ClassEntries[dwIndex].fCacheHit;
  368. *pdwEntryType = _ClassEntries[dwIndex].dwElementType;
  369. switch(_ClassEntries[dwIndex].dwElementType) {
  370. case DOMAIN_ENTRY_TYPE:
  371. wcscpy(pszName, _ClassEntries[dwIndex].u.pszPDCName);
  372. break;
  373. case COMPUTER_ENTRY_TYPE:
  374. wcscpy(pszName, _ClassEntries[dwIndex].u.pszDomainName);
  375. break;
  376. case DOMAIN_ENTRY_TYPE_RO:
  377. wcscpy(pszName, _ClassEntries[dwIndex].u.pszDCName);
  378. break;
  379. default:
  380. wcscpy(pszName, TEXT(""));
  381. break;
  382. }
  383. error:
  384. LeaveCriticalSection(&_cs);
  385. RRETURN(hr);
  386. }
  387. HRESULT
  388. CObjNameCache::
  389. InvalidateStaleEntries()
  390. {
  391. DWORD i=0;
  392. SYSTEMTIME stCurrentTime;
  393. BOOL fCacheHit;
  394. GetSystemTime(&stCurrentTime);
  395. for ( i=0; i< _dwMaxCacheSize; i++){
  396. fCacheHit = _ClassEntries[i].fCacheHit;
  397. if(_ClassEntries[i].bInUse &&
  398. TimeDifference(stCurrentTime, _ClassEntries[i].st)
  399. > AGE_LIMIT_VALID_ENTRIES && fCacheHit == CACHE_HIT) {
  400. _ClassEntries[i].bInUse = FALSE;
  401. FreeADsStr(_ClassEntries[i].pszElementName);
  402. _ClassEntries[i].pszElementName = NULL;
  403. if((_ClassEntries[i].dwElementType == DOMAIN_ENTRY_TYPE) ||
  404. (_ClassEntries[i].dwElementType == DOMAIN_ENTRY_TYPE_RO))
  405. {
  406. FreeADsStr(_ClassEntries[i].u.pszPDCName);
  407. _ClassEntries[i].u.pszPDCName = NULL;
  408. } else if (_ClassEntries[i].dwElementType == COMPUTER_ENTRY_TYPE){
  409. FreeADsStr(_ClassEntries[i].u.pszDomainName);
  410. _ClassEntries[i].u.pszPDCName = NULL;
  411. }
  412. }else if(_ClassEntries[i].bInUse &&
  413. TimeDifference(stCurrentTime, _ClassEntries[i].st)
  414. > AGE_LIMIT_INVALID_ENTRIES && fCacheHit == CACHE_MISS) {
  415. _ClassEntries[i].bInUse = FALSE;
  416. }
  417. }
  418. RRETURN(S_OK);
  419. }
  420. //+------------------------------------------------------------------------
  421. //
  422. // Function: CObjNameCache
  423. //
  424. // Synopsis:
  425. //
  426. //
  427. //
  428. // Arguments:
  429. //
  430. //
  431. //-------------------------------------------------------------------------
  432. CObjNameCache::CObjNameCache() :
  433. _fCriticalSectionInitialized(FALSE)
  434. {
  435. _dwMaxCacheSize = 10;
  436. memset(_ClassEntries, 0, sizeof(CLASSENTRY)* MAX_ENTRIES);
  437. }
  438. //+------------------------------------------------------------------------
  439. //
  440. // Function: ~CObjNameCache
  441. //
  442. // Synopsis:
  443. //
  444. //
  445. //
  446. // Arguments:
  447. //
  448. //
  449. //-------------------------------------------------------------------------
  450. CObjNameCache::
  451. ~CObjNameCache()
  452. {
  453. DWORD i= 0;
  454. for (i=0; i< MAX_ENTRIES; i++){
  455. if(_ClassEntries[i].pszElementName){
  456. FreeADsStr(_ClassEntries[i].pszElementName);
  457. }
  458. //
  459. // All members of the union are strings so it is not
  460. // necessary to check for each of the members.
  461. //
  462. if(_ClassEntries[i].u.pszPDCName){
  463. FreeADsStr(_ClassEntries[i].u.pszPDCName);
  464. }
  465. }
  466. if (_fCriticalSectionInitialized)
  467. DeleteCriticalSection(&_cs);
  468. }
  469. //+------------------------------------------------------------------------
  470. //
  471. // Function:
  472. //
  473. // Synopsis:
  474. //
  475. //
  476. //
  477. // Arguments:
  478. //
  479. //
  480. //-------------------------------------------------------------------------
  481. HRESULT
  482. CObjNameCache::
  483. CreateClassCache(
  484. CObjNameCache FAR *FAR * ppClassCache
  485. )
  486. {
  487. CObjNameCache FAR * pClassCache = NULL;
  488. pClassCache = new CObjNameCache();
  489. if (!pClassCache) {
  490. RRETURN(E_FAIL);
  491. }
  492. __try
  493. {
  494. InitializeCriticalSection(&(pClassCache->_cs));
  495. pClassCache->_fCriticalSectionInitialized = TRUE;
  496. }
  497. __except (EXCEPTION_EXECUTE_HANDLER)
  498. {
  499. RRETURN(E_OUTOFMEMORY);
  500. }
  501. *ppClassCache = pClassCache;
  502. RRETURN(S_OK);
  503. }
  504. DWORD
  505. CObjNameCache::
  506. IsOlderThan(
  507. DWORD i,
  508. DWORD j
  509. )
  510. {
  511. SYSTEMTIME *pi, *pj;
  512. DWORD iMs, jMs;
  513. // DBGMSG(DBG_TRACE, ("IsOlderThan entering with i %d j %d\n", i, j));
  514. pi = &(_ClassEntries[i].st);
  515. pj = &(_ClassEntries[j].st);
  516. if (pi->wYear < pj->wYear) {
  517. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  518. return(i);
  519. } else if (pi->wYear > pj->wYear) {
  520. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  521. return(j);
  522. } else if (pi->wMonth < pj->wMonth) {
  523. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  524. return(i);
  525. } else if (pi->wMonth > pj->wMonth) {
  526. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  527. return(j);
  528. } else if (pi->wDay < pj->wDay) {
  529. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  530. return(i);
  531. } else if (pi->wDay > pj->wDay) {
  532. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  533. return(j);
  534. } else {
  535. iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
  536. jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
  537. if (iMs <= jMs) {
  538. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  539. return(i);
  540. } else {
  541. // DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
  542. return(j);
  543. }
  544. }
  545. }
  546. HRESULT
  547. WinNTGetCachedDCName(
  548. LPWSTR pszDomainName,
  549. LPWSTR pszPDCName,
  550. DWORD dwFlags
  551. )
  552. {
  553. WCHAR szSAMName[MAX_PATH];
  554. // In this case credentials do not help because we do not have
  555. // any server/domain to connect to. This is because the param
  556. // pszDomainName is not a domain name for certain.
  557. CWinNTCredentials nullCredentials;
  558. // We do want to copy the flags parameter as that will tell
  559. // us if we need to connect to PDC or not
  560. nullCredentials.SetFlags(dwFlags);
  561. RRETURN(WinNTGetCachedObject(pszDomainName,
  562. DOMAIN_ENTRY_TYPE,
  563. pszPDCName,
  564. szSAMName,
  565. dwFlags,
  566. nullCredentials
  567. ));
  568. }
  569. HRESULT
  570. WinNTGetCachedComputerName(
  571. LPWSTR pszComputerName,
  572. LPWSTR pszName,
  573. LPWSTR pszSAMName,
  574. CWinNTCredentials& Credentials
  575. )
  576. {
  577. RRETURN(WinNTGetCachedObject(pszComputerName,
  578. COMPUTER_ENTRY_TYPE,
  579. pszName,
  580. pszSAMName,
  581. Credentials.GetFlags(), // doesnt matter
  582. Credentials
  583. ));
  584. }
  585. HRESULT
  586. WinNTGetCachedObject(
  587. LPWSTR pszElementName,
  588. DWORD dwElementType,
  589. LPWSTR pszName,
  590. LPWSTR pszSAMName,
  591. DWORD dwFlags,
  592. CWinNTCredentials& Credentials
  593. )
  594. {
  595. HRESULT hr = S_OK;
  596. NET_API_STATUS nasStatus = 0;
  597. BOOL fCacheHit;
  598. DWORD dwEntryType;
  599. LPWKSTA_INFO_100 lpWI = NULL;
  600. DWORD dwObjectsReturned;
  601. DWORD dwObjectsTotal;
  602. DWORD dwResumeHandle;
  603. // Freed using NetAPI
  604. LPWSTR pszServerName = NULL;
  605. // Freed using FreeADsStr
  606. LPWSTR pszADsStrServerName = NULL;
  607. BOOL fRefAdded = FALSE;
  608. DWORD dwDomainEntryType = DOMAIN_ENTRY_TYPE;
  609. // This will be the case most often
  610. DWORD dwUserFlags = Credentials.GetFlags();
  611. DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomainInfo = NULL;
  612. BOOL fNetBIOS = FALSE;
  613. BOOL fDsRoleCallAttempted = FALSE;
  614. hr = pgPDCNameCache->getentry(
  615. pszElementName,
  616. &fCacheHit,
  617. &dwEntryType,
  618. pszName
  619. );
  620. if (SUCCEEDED(hr)) {
  621. //
  622. // we found the entry. Now need to verify that it indeed
  623. // is an object of type desired
  624. //
  625. // Note that dwElement type will never be DOMAIN_ENTRY_TYPE_RO
  626. if(fCacheHit) {
  627. if (dwEntryType == dwElementType
  628. || ((dwElementType == DOMAIN_ENTRY_TYPE)
  629. && (dwEntryType == DOMAIN_ENTRY_TYPE_RO)
  630. && (dwUserFlags & ADS_READONLY_SERVER))
  631. ) {
  632. //
  633. // If the user now needs a writeable connection
  634. // should we fail or should we actually pretend
  635. // that the object is not there in the cache.
  636. //
  637. hr = S_OK;
  638. goto error;
  639. }
  640. } else if (!fCacheHit && (dwElementType == WORKGROUP_ENTRY_TYPE)) {
  641. //
  642. // looks like we either found a cache miss
  643. // Return ok
  644. //
  645. hr = S_OK;
  646. goto error;
  647. } else {
  648. hr = E_FAIL;
  649. goto error;
  650. }
  651. }
  652. switch(dwElementType){
  653. case DOMAIN_ENTRY_TYPE:
  654. //
  655. // A read only server is ok, need to also set the
  656. // domain entry type accordingly
  657. //
  658. if (dwFlags & ADS_READONLY_SERVER) {
  659. dwDomainEntryType = DOMAIN_ENTRY_TYPE_RO;
  660. }
  661. //
  662. // Call the all encompassing Wrapper.
  663. //
  664. hr = DsGetDcNameNTWrapper(
  665. pszElementName,
  666. &pszADsStrServerName,
  667. dwFlags
  668. );
  669. BAIL_ON_FAILURE(hr);
  670. hr = pgPDCNameCache->addentry(
  671. pszElementName,
  672. TRUE,
  673. dwDomainEntryType,
  674. pszADsStrServerName
  675. );
  676. BAIL_ON_FAILURE(hr);
  677. //
  678. // in addition we can also add a computer entry for the PDC
  679. //
  680. hr = pgPDCNameCache->addentry(
  681. pszADsStrServerName+2, // to get rid of the leading backslashes
  682. TRUE,
  683. COMPUTER_ENTRY_TYPE,
  684. pszElementName
  685. );
  686. BAIL_ON_FAILURE(hr);
  687. wcscpy(pszName, pszADsStrServerName);
  688. break;
  689. case COMPUTER_ENTRY_TYPE:
  690. // Ref the computer, note that RefServer will not
  691. // do anything if the credentials are null. We are also
  692. // not worried about errors as we want to use default
  693. // credentials in that case.
  694. hr = Credentials.RefServer(pszElementName);
  695. if (SUCCEEDED(hr)) {
  696. fRefAdded = TRUE;
  697. }
  698. nasStatus = NetWkstaGetInfo(
  699. pszElementName,
  700. 100,
  701. (LPBYTE*) &lpWI
  702. );
  703. hr = HRESULT_FROM_WIN32(nasStatus);
  704. BAIL_ON_FAILURE(hr);
  705. #ifdef WIN95
  706. //
  707. // No NetpNameCompare for Win9x
  708. //
  709. if (lpWI->wki100_computername
  710. && (_wcsicmp(pszElementName, lpWI->wki100_computername) == 0)
  711. )
  712. #else
  713. if (lpWI->wki100_computername
  714. && ( NetpNameCompare(
  715. NULL,
  716. pszElementName,
  717. lpWI->wki100_computername,
  718. NAMETYPE_COMPUTER,
  719. 0
  720. )
  721. == 0 )
  722. )
  723. #endif
  724. {
  725. // Want to add the correct capitalized name
  726. // Not what the user gave
  727. hr = pgPDCNameCache->addentry(
  728. lpWI->wki100_computername,
  729. TRUE,
  730. COMPUTER_ENTRY_TYPE,
  731. lpWI->wki100_langroup
  732. );
  733. wcscpy(pszSAMName, lpWI->wki100_computername);
  734. fNetBIOS = TRUE;
  735. }
  736. else {
  737. DsRoleGetPrimaryDomainInformation(
  738. pszElementName,
  739. DsRolePrimaryDomainInfoBasic, // InfoLevel
  740. (PBYTE*)&pdomainInfo // pBuffer
  741. );
  742. fDsRoleCallAttempted = TRUE;
  743. // we don't bail out even if the call fails
  744. //
  745. // user actually passes in ipaddress as the computer name
  746. //
  747. if(IsAddressNumeric(pszElementName)) {
  748. hr = pgPDCNameCache->addentry(
  749. pszElementName,
  750. TRUE,
  751. COMPUTER_ENTRY_TYPE,
  752. pdomainInfo && pdomainInfo->DomainNameDns ? pdomainInfo->DomainNameDns : lpWI->wki100_langroup
  753. );
  754. wcscpy(pszSAMName, L"");
  755. }
  756. //
  757. // user may pass in the dns name of the computer
  758. //
  759. else {
  760. if(pdomainInfo) {
  761. if(((pdomainInfo->DomainNameDns) && _wcsicmp(pszElementName, pdomainInfo->DomainNameDns) == 0)
  762. ||
  763. ((pdomainInfo->DomainNameFlat) && NetpNameCompare(
  764. NULL,
  765. pszElementName,
  766. pdomainInfo->DomainNameFlat,
  767. NAMETYPE_COMPUTER,
  768. 0
  769. )
  770. == 0) )
  771. {
  772. BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
  773. }
  774. else {
  775. hr = pgPDCNameCache->addentry(
  776. pszElementName,
  777. TRUE,
  778. COMPUTER_ENTRY_TYPE,
  779. pdomainInfo->DomainNameDns
  780. );
  781. wcscpy(pszSAMName, L"");
  782. }
  783. }
  784. else {
  785. BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
  786. }
  787. }
  788. }
  789. // we need to return the correct format of domain name
  790. if(!(*pszName))
  791. {
  792. // the parent name is NULL
  793. if(fNetBIOS)
  794. {
  795. // if the user specifies the computer netbios name, then we just return the domain netbios name
  796. wcscpy(pszName, lpWI->wki100_langroup);
  797. }
  798. else
  799. {
  800. // othereise we tries to return the domain dns name
  801. wcscpy(pszName, pdomainInfo && pdomainInfo->DomainNameDns ? pdomainInfo->DomainNameDns : lpWI->wki100_langroup);
  802. }
  803. }
  804. else
  805. {
  806. // we have the parent name passed in, so we need to return pszName accordingly
  807. if (lpWI->wki100_langroup
  808. && ( NetpNameCompare(
  809. NULL,
  810. pszName,
  811. lpWI->wki100_langroup,
  812. NAMETYPE_DOMAIN,
  813. 0
  814. )
  815. ))
  816. {
  817. // the parent name passed in is not equal to the domain netbios name
  818. if(!fDsRoleCallAttempted)
  819. {
  820. DsRoleGetPrimaryDomainInformation(
  821. pszElementName,
  822. DsRolePrimaryDomainInfoBasic, // InfoLevel
  823. (PBYTE*)&pdomainInfo // pBuffer
  824. );
  825. }
  826. // unless the the parent name passed in is equal to the domain dns name, we just put domain netbios name
  827. // to the pszName
  828. if(!(pdomainInfo && pdomainInfo->DomainNameDns && !_wcsicmp(pszName, pdomainInfo->DomainNameDns)))
  829. {
  830. // the parent name passed in is not equal to the domain dns name also
  831. wcscpy(pszName, lpWI->wki100_langroup);
  832. }
  833. }
  834. }
  835. break;
  836. default:
  837. hr = E_FAIL;
  838. break;
  839. }
  840. error:
  841. if (fRefAdded) {
  842. Credentials.DeRefServer();
  843. // even if we fail, we have no recovery path
  844. fRefAdded = FALSE;
  845. }
  846. if(lpWI){
  847. NetApiBufferFree(lpWI);
  848. }
  849. if(pszServerName){
  850. NetApiBufferFree(pszServerName);
  851. }
  852. if (pszADsStrServerName) {
  853. FreeADsStr(pszADsStrServerName);
  854. }
  855. if ( pdomainInfo )
  856. {
  857. DsRoleFreeMemory(pdomainInfo);
  858. }
  859. RRETURN(hr);
  860. }
  861. //+------------------------------------------------------------------------
  862. //
  863. // Function:
  864. //
  865. // Synopsis:
  866. // This function is called by Heuristic GetObject to identify what
  867. // kind of object we are dealing with. Here we try to get a cached
  868. // entry if it is a hit/miss. If it fails, then we try each kind
  869. // of object in turn. (Domain/Computer/Workgroup). Once we do this,
  870. // we cache this information internally
  871. //
  872. //
  873. //
  874. // Arguments:
  875. //
  876. //
  877. //-------------------------------------------------------------------------
  878. HRESULT
  879. WinNTGetCachedName(
  880. LPWSTR pszElementName,
  881. PDWORD pdwElementType,
  882. LPWSTR pszName,
  883. LPWSTR pszSAMName,
  884. CWinNTCredentials& Credentials
  885. )
  886. {
  887. HRESULT hr = S_OK;
  888. BOOL fCacheHit;
  889. DWORD dwEntryType;
  890. WCHAR szSAMName[MAX_ADS_PATH];
  891. BOOL fRefAdded = FALSE;
  892. DWORD dwUserFlags = Credentials.GetFlags();
  893. szSAMName[0] = pszName[0] = L'\0';
  894. if (!pszElementName || !*pszElementName) {
  895. RRETURN(E_FAIL);
  896. }
  897. hr = pgPDCNameCache->getentry(
  898. pszElementName,
  899. &fCacheHit,
  900. &dwEntryType,
  901. pszName
  902. );
  903. if (SUCCEEDED(hr)) {
  904. //
  905. // we found the entry.
  906. //
  907. if (!fCacheHit){
  908. //
  909. // cache miss saved as a workgroup
  910. //
  911. *pdwElementType = WORKGROUP_ENTRY_TYPE;
  912. goto error;
  913. } else {
  914. if(dwEntryType == DOMAIN_ENTRY_TYPE_RO) {
  915. if(dwUserFlags & ADS_READONLY_SERVER) {
  916. // HeuristicGetObj doesn't recognize DOMAIN_ENTRY_TYPE_RO
  917. *pdwElementType = DOMAIN_ENTRY_TYPE;
  918. goto error;
  919. }
  920. }
  921. else {
  922. *pdwElementType = dwEntryType;
  923. goto error;
  924. }
  925. }
  926. }
  927. {
  928. // at this point, we can try and ref the domain as
  929. // we are looking to bind to the domain
  930. hr = Credentials.RefDomain(pszElementName);
  931. // note that even if this fails we want to continue
  932. // as there is the chance that the current users
  933. // credentials are good enough for the operation
  934. if (SUCCEEDED(hr)) {
  935. fRefAdded = TRUE;
  936. }
  937. hr = WinNTGetCachedObject(
  938. pszElementName,
  939. DOMAIN_ENTRY_TYPE,
  940. pszName,
  941. szSAMName,
  942. Credentials.GetFlags(),
  943. Credentials
  944. );
  945. if (fRefAdded) {
  946. Credentials.DeRefDomain();
  947. // we cannot really do anything useful with HR
  948. fRefAdded = FALSE;
  949. }
  950. if (SUCCEEDED(hr)){
  951. *pdwElementType = DOMAIN_ENTRY_TYPE;
  952. wcscpy(pszSAMName, szSAMName);
  953. RRETURN(hr);
  954. }
  955. hr = WinNTGetCachedObject(
  956. pszElementName,
  957. COMPUTER_ENTRY_TYPE,
  958. pszName,
  959. szSAMName,
  960. Credentials.GetFlags(),
  961. Credentials
  962. );
  963. if (SUCCEEDED(hr)){
  964. *pdwElementType = COMPUTER_ENTRY_TYPE;
  965. wcscpy(pszSAMName, szSAMName);
  966. RRETURN(hr);
  967. }
  968. //
  969. // if you are here, it means that you have to cache a miss as a
  970. // workgroup.
  971. // Note that pszSAMName rather than pszElementName is added
  972. // if it is valid
  973. // AjayR - to handle the no workstation case,
  974. // We should not add anything if the error was NOWksta service
  975. if (hr != HRESULT_FROM_WIN32(NERR_WkstaNotStarted)) {
  976. if (szSAMName[0] != L'\0') {
  977. hr = pgPDCNameCache->addentry(
  978. szSAMName,
  979. FALSE,
  980. WORKGROUP_ENTRY_TYPE,
  981. TEXT("")
  982. );
  983. } else {
  984. hr = pgPDCNameCache->addentry(
  985. pszElementName,
  986. FALSE,
  987. WORKGROUP_ENTRY_TYPE,
  988. TEXT("")
  989. );
  990. }
  991. } // No Wksta started
  992. *pdwElementType = WORKGROUP_ENTRY_TYPE;
  993. wcscpy(pszName, TEXT(""));
  994. goto error;
  995. }
  996. error:
  997. RRETURN(hr);
  998. }
  999. LONG
  1000. TimeDifference(
  1001. SYSTEMTIME st1,
  1002. SYSTEMTIME st2
  1003. )
  1004. {
  1005. //
  1006. // This function gives the difference between st1 and st2 (st1-st2)in secs.
  1007. // This will be used by our internal cache object so as to find out if
  1008. // a certain entry in the cache is too old.
  1009. // Assumption: st1 is later than st2.
  1010. DWORD dwTime1;
  1011. DWORD dwTime2;
  1012. DWORD dwMonth1;
  1013. DWORD dwMonth2;
  1014. LONG lRetval;
  1015. //
  1016. // Ignore milliseconds because it is immaterial for our purposes
  1017. //
  1018. dwTime1= st1.wSecond + 60 *
  1019. (st1.wMinute + 60* (st1.wHour + 24 * (st1.wDay)));
  1020. dwTime2= st2.wSecond + 60 *
  1021. (st2.wMinute + 60* (st2.wHour + 24 * (st2.wDay)));
  1022. if (dwTime1 == dwTime2) {
  1023. return(0);
  1024. }
  1025. if (dwTime1 > dwTime2 && (st1.wMonth == st2.wMonth) &&
  1026. st1.wYear == st2.wYear) {
  1027. lRetval = (LONG)(dwTime1-dwTime2);
  1028. goto cleanup;
  1029. }
  1030. dwMonth1 = 12*st1.wYear+ st1.wMonth;
  1031. dwMonth2 = 12*st2.wYear+ st2.wMonth;
  1032. if (dwMonth1 < dwMonth2) {
  1033. //
  1034. // looks like we got a bogus value. return -1
  1035. //
  1036. lRetval = -1;
  1037. goto cleanup;
  1038. }
  1039. //
  1040. // if there is a month difference of more than 1 then we return
  1041. // a large positive number (0xFFFFFFF)
  1042. //
  1043. if (dwMonth1 > dwMonth2+1) {
  1044. lRetval = 0xFFFFFFF;
  1045. goto cleanup;
  1046. }
  1047. //
  1048. // we crossed a month boundary
  1049. //
  1050. dwTime1= st1.wSecond + 60 *
  1051. (st1.wMinute + 60* (st1.wHour));
  1052. dwTime2= st2.wSecond + 60 *
  1053. (st2.wMinute);
  1054. lRetval = ( dwTime2- dwTime1 + 60*60*24);
  1055. goto cleanup;
  1056. cleanup:
  1057. return(lRetval);
  1058. }
  1059. BOOL
  1060. IsAddressNumeric(
  1061. LPWSTR HostName
  1062. )
  1063. {
  1064. BOOLEAN rc = FALSE;
  1065. //
  1066. // to check to see if it's a TCP address, we check for it to only
  1067. // contain only numerals and periods.
  1068. //
  1069. while (((*HostName >= L'0') && (*HostName <= L'9')) ||
  1070. (*HostName == L'.')) {
  1071. HostName++;
  1072. }
  1073. //
  1074. // if we hit the end of the hostname, then it's an address.
  1075. //
  1076. if (*HostName == L'\0' || *HostName == L':') {
  1077. rc = TRUE;
  1078. }
  1079. return rc;
  1080. }