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.

732 lines
20 KiB

  1. //#--------------------------------------------------------------
  2. //
  3. // File: infohelper.cpp
  4. //
  5. // Synopsis: Implementation of helper methods
  6. // which are used by the sdoserverinfo COM object
  7. //
  8. //
  9. // History: 06/08/98 MKarki Created
  10. //
  11. // Copyright (C) 1997-98 Microsoft Corporation
  12. // All rights reserved.
  13. //
  14. //----------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "infohelper.h"
  17. #include "sdoias.h"
  18. #include "dsconnection.h"
  19. #include <lmcons.h>
  20. #include <lmwksta.h>
  21. #include <lmserver.h>
  22. #include <lmerr.h>
  23. #include <winldap.h>
  24. #include <explicitlink.h>
  25. #include <lmaccess.h>
  26. #include <lmapibuf.h>
  27. #include <activeds.h>
  28. #include <winsock2.h>
  29. //
  30. // reg key to be queried
  31. //
  32. const WCHAR PRODUCT_OPTIONS_REGKEY [] =
  33. L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
  34. //
  35. // maximum Domain name
  36. //
  37. const DWORD MAX_DOMAINNAME_LENGTH = 1024;
  38. //
  39. // this holds the matrix to get SYSTEMTYPE from the
  40. // NTTYPE and VERSION type
  41. //
  42. const IASOSTYPE g_OsInfoTable [2][2] = {
  43. SYSTEM_TYPE_NT4_WORKSTATION,
  44. SYSTEM_TYPE_NT5_WORKSTATION,
  45. SYSTEM_TYPE_NT4_SERVER,
  46. SYSTEM_TYPE_NT5_SERVER
  47. };
  48. //++--------------------------------------------------------------
  49. //
  50. // Function: SdoGetOSInfo
  51. //
  52. // Synopsis: This is method used to get OS System information
  53. // Currently it returns the following info:
  54. // 1) Os Version: 4 or 5
  55. // 2) NtType: Wks or Svr
  56. //
  57. // Arguments:
  58. // LPCWSTR - machine name
  59. // PSYSTEMTYPE - info to be returned
  60. //
  61. // Returns: HRESULT
  62. //
  63. // History: MKarki Created 06/08/98
  64. //
  65. //----------------------------------------------------------------
  66. HRESULT
  67. SdoGetOSInfo (
  68. /*[in]*/ LPCWSTR lpServerName,
  69. /*[out]*/ PIASOSTYPE pSystemType
  70. )
  71. {
  72. HRESULT hr = S_OK;
  73. NTVERSION eNtVersion;
  74. NTTYPE eNtType;
  75. _ASSERT ((NULL != lpServerName) && (NULL != pSystemType));
  76. do
  77. {
  78. //
  79. // get the OS Version now
  80. //
  81. hr = ::GetNTVersion (lpServerName, &eNtVersion);
  82. if (FAILED (hr))
  83. {
  84. IASTracePrintf(
  85. "Error in SDO - SdoGetOSInfo() - GetNTVersion() failed..."
  86. );
  87. break;
  88. }
  89. //
  90. // get the OS type - NT Server or Workstation
  91. //
  92. hr = ::IsWorkstationOrServer (lpServerName, &eNtType);
  93. if (FAILED (hr))
  94. {
  95. IASTracePrintf(
  96. "Error in SDO - SdoGetOSInfo()"
  97. "- IsWorkstationOrServer() failed..."
  98. );
  99. break;
  100. }
  101. //
  102. // now decide which machine type this is
  103. //
  104. *pSystemType = g_OsInfoTable [eNtType][eNtVersion];
  105. } while (FALSE);
  106. return (hr);
  107. } // end of ::SdoServerInfo method
  108. //++--------------------------------------------------------------
  109. //
  110. // Function: SdoGetDomainInfo
  111. //
  112. // Synopsis: This is method used to get the domain type
  113. // information
  114. //
  115. // Arguments:
  116. // LPCWSTR - machine name
  117. // LPCWSTR - Domain name
  118. // PDOMAINTYPE - Domain Info
  119. //
  120. // Returns: HRESULT
  121. //
  122. // History: MKarki Created 06/08/98
  123. //
  124. //----------------------------------------------------------------
  125. HRESULT
  126. SdoGetDomainInfo (
  127. /*[in]*/ LPCWSTR pszServerName,
  128. /*[in]*/ LPCWSTR pszDomainName,
  129. /*[out]*/ PIASDOMAINTYPE pDomainType
  130. )
  131. {
  132. HRESULT hr = S_OK;
  133. BOOL bHasDC = FALSE;
  134. BOOL bHasDS = FALSE;
  135. BOOL bMixed = FALSE;
  136. LPBYTE pNetBuffer = NULL;
  137. WCHAR szGeneratedDomainName [MAX_DOMAINNAME_LENGTH + 3];
  138. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  139. _ASSERT (pDomainType);
  140. //
  141. // get the domain information by calling DsGetDcName
  142. // where this API is supported
  143. //
  144. DWORD dwErr = ::DsGetDcName (
  145. pszServerName,
  146. pszDomainName,
  147. NULL,
  148. NULL,
  149. DS_FORCE_REDISCOVERY |
  150. DS_DIRECTORY_SERVICE_PREFERRED,
  151. &pDCInfo
  152. );
  153. if (NO_ERROR == dwErr)
  154. {
  155. //
  156. // we sure have a domain controller
  157. //
  158. bHasDC = TRUE;
  159. //
  160. // check if DS is available
  161. //
  162. bHasDS = ((pDCInfo->Flags & DS_DS_FLAG) != 0);
  163. if (NULL == pszDomainName)
  164. {
  165. pszDomainName = pDCInfo->DomainName;
  166. }
  167. }
  168. else if (ERROR_NO_SUCH_DOMAIN == dwErr)
  169. {
  170. IASTracePrintf(
  171. "Error in SDO - SdoGetDomainInfo()"
  172. " - domain could not be located..."
  173. );
  174. }
  175. else
  176. {
  177. IASTracePrintf(
  178. "Error in SDO - SdoGetDomainInfo()"
  179. " - DsGetDcName(DS_PREFERRED) failed with error:%d",
  180. dwErr
  181. );
  182. hr = HRESULT_FROM_WIN32 (dwErr);
  183. goto Cleanup;
  184. }
  185. #if 0
  186. //
  187. // case of NT4 - which we don't support as of now
  188. //
  189. else
  190. {
  191. WCHAR szShortDomainName[MAX_DOMAINNAME_LENGTH +2];
  192. if (NULL != pszDomainName)
  193. {
  194. lstrcpy (szShortDomainName, pszDomainName);
  195. PWCHAR pTemp = wcschr (szShortDomainName, L'.');
  196. if (NULL != pTemp)
  197. {
  198. *pTemp = L'\0';
  199. }
  200. }
  201. //
  202. // DsGetDcName not availabe so call NetGetDCName
  203. // could be Nt 4 machine
  204. //
  205. LPBYTE pNetBuffer = NULL;
  206. NET_API_STATUS status = ::NetGetAnyDCName (
  207. pszServerName,
  208. (NULL == pszDomainName) ?
  209. NULL:szShortDomainName,
  210. &pNetBuffer
  211. );
  212. if (NERR_Success != status)
  213. {
  214. IASTracePrintf(
  215. "Error in SDO - SdoGetDomainInfo()"
  216. " -NetGetAnyDCName (ANY_DOMAIN) failed with error:%d",
  217. status
  218. );
  219. }
  220. else
  221. {
  222. //
  223. // we sure have a domain controller
  224. //
  225. bHasDC = TRUE;
  226. //
  227. // get domain name if we don't have one already
  228. //
  229. if (NULL == pszDomainName)
  230. {
  231. hr = ::SdoGetDomainName (pszServerName, szGeneratedDomainName);
  232. if (FAILED (hr))
  233. {
  234. IASTracePrintf(
  235. "Error in SDO - SdoGetDomainInfo()"
  236. " - SdoGetDomainName() failed with error:%x",
  237. hr
  238. );
  239. goto Cleanup;
  240. }
  241. }
  242. //
  243. // skip the leading "\\"
  244. //
  245. PWCHAR pDomainServerName =
  246. 2 + reinterpret_cast <PWCHAR>(pNetBuffer);
  247. //
  248. // try connecting to LDAP port on this server
  249. //
  250. LDAP *ld = ldap_openW (
  251. const_cast <PWCHAR> (pDomainServerName),
  252. LDAP_PORT
  253. );
  254. bHasDS = ld ? ldap_unbind (ld), TRUE:FALSE;
  255. }
  256. }
  257. #endif
  258. //
  259. // if we have NT5 DC, check if its mixed or native domain
  260. //
  261. if (TRUE == bHasDS)
  262. {
  263. hr = ::IsMixedDomain (pszDomainName, &bMixed);
  264. if (FAILED (hr))
  265. {
  266. IASTracePrintf(
  267. "Error in SDO - SdoGetOSInfo()"
  268. " - IsMixedDomain() failed with errror:%x",
  269. hr
  270. );
  271. }
  272. }
  273. //
  274. // now set the info in the pDomainInfo struct
  275. //
  276. if (SUCCEEDED (hr))
  277. {
  278. if (bMixed)
  279. *pDomainType = DOMAIN_TYPE_MIXED;
  280. else if (bHasDS)
  281. *pDomainType = DOMAIN_TYPE_NT5;
  282. else if (bHasDC)
  283. *pDomainType = DOMAIN_TYPE_NT4;
  284. else
  285. *pDomainType = DOMAIN_TYPE_NONE;
  286. }
  287. //
  288. // cleanup here
  289. //
  290. Cleanup:
  291. if (NULL != pDCInfo)
  292. ::NetApiBufferFree (pDCInfo);
  293. if (NULL != pNetBuffer)
  294. ::NetApiBufferFree (pNetBuffer);
  295. return (hr);
  296. } // end of SdoGetDomainInfo method
  297. //++--------------------------------------------------------------
  298. //
  299. // Function: IsWorkstationOrServer
  300. //
  301. // Synopsis: This is method determines if a specific machine
  302. // is running NT workstation or Server
  303. //
  304. // Arguments:
  305. // LPCWSTR - machine name
  306. // NTTYPE*
  307. //
  308. // Returns: HRESULT
  309. //
  310. // History: MKarki Created 06/08/98
  311. //
  312. //----------------------------------------------------------------
  313. HRESULT
  314. IsWorkstationOrServer (
  315. /*[in]*/ LPCWSTR pszComputerName,
  316. /*[out]*/ NTTYPE *pNtType
  317. )
  318. {
  319. HRESULT hr = S_OK;
  320. WCHAR szCompleteName [IAS_MAX_SERVER_NAME + 3];
  321. PWCHAR pszTempName = const_cast <PWCHAR> (pszComputerName);
  322. _ASSERT ((NULL != pszComputerName) && (NULL != pNtType));
  323. do
  324. {
  325. //
  326. // the computer name should have a "\\" in front
  327. //
  328. if ((L'\\' != *pszComputerName) || (L'\\' != *(pszComputerName + 1)))
  329. {
  330. if (::wcslen (pszComputerName) > IAS_MAX_SERVER_NAME)
  331. {
  332. IASTracePrintf(
  333. "Error in Server Info SDO - IsWorkstationOrServer()"
  334. " - Computer name is too big..."
  335. );
  336. hr = E_FAIL;
  337. break;
  338. }
  339. ::wcscpy (szCompleteName, L"\\\\");
  340. ::wcscat (szCompleteName, pszComputerName);
  341. pszTempName = szCompleteName;
  342. }
  343. //
  344. // Connect to the registry
  345. //
  346. HKEY hResult;
  347. DWORD dwErr = ::RegConnectRegistry (
  348. pszTempName,
  349. HKEY_LOCAL_MACHINE,
  350. &hResult
  351. );
  352. if (ERROR_SUCCESS != dwErr)
  353. {
  354. IASTracePrintf(
  355. "Error in SDO - IsWorkstationOrServer()"
  356. " - RegConnectRegistry() failed with error:%d",
  357. dwErr
  358. );
  359. hr = HRESULT_FROM_WIN32 (dwErr);
  360. break;
  361. }
  362. //
  363. // open the registry key now
  364. //
  365. HKEY hValueKey;
  366. dwErr = ::RegOpenKeyEx (
  367. hResult,
  368. PRODUCT_OPTIONS_REGKEY,
  369. 0,
  370. KEY_QUERY_VALUE,
  371. &hValueKey
  372. );
  373. if (ERROR_SUCCESS != dwErr)
  374. {
  375. IASTracePrintf(
  376. "Error in SDO - IsWorkstationOrServer()"
  377. " - RegOpenKeyEx() failed with error:%d",
  378. hr
  379. );
  380. RegCloseKey (hResult);
  381. hr = HRESULT_FROM_WIN32 (dwErr);
  382. break;
  383. }
  384. //
  385. // get the value now
  386. //
  387. WCHAR szProductType [MAX_PATH];
  388. DWORD dwBufferLength = MAX_PATH;
  389. dwErr = RegQueryValueEx (
  390. hValueKey,
  391. L"ProductType",
  392. NULL,
  393. NULL,
  394. (LPBYTE)szProductType,
  395. &dwBufferLength
  396. );
  397. if (ERROR_SUCCESS != dwErr)
  398. {
  399. IASTracePrintf(
  400. "Error in SDO - IsWorkstationOrServer()"
  401. " - RegQueryValueEx() failed with error:%d",
  402. hr
  403. );
  404. RegCloseKey (hValueKey);
  405. RegCloseKey (hResult);
  406. hr = HRESULT_FROM_WIN32 (dwErr);
  407. }
  408. //
  409. // determine which NT Type we have on this machine
  410. //
  411. if (_wcsicmp (L"WINNT", szProductType) == 0)
  412. {
  413. *pNtType = NT_WKSTA;
  414. }
  415. else if (!_wcsicmp (L"SERVERNT", szProductType) ||
  416. !_wcsicmp (L"LanmanNT", szProductType))
  417. {
  418. *pNtType = NT_SVR;
  419. }
  420. else
  421. {
  422. IASTracePrintf(
  423. "Error in SDO - IsWorkstationOrServer()"
  424. " - Could not determine machine type..."
  425. );
  426. RegCloseKey (hValueKey);
  427. RegCloseKey (hResult);
  428. hr = E_FAIL;
  429. }
  430. //
  431. // cleanup
  432. //
  433. RegCloseKey (hValueKey);
  434. RegCloseKey (hResult);
  435. } while (FALSE);
  436. return (hr);
  437. } // end of ::IsWorkstationOrServer method
  438. //++--------------------------------------------------------------
  439. //
  440. // Function: GetNTVersion
  441. //
  442. // Synopsis: This is method determines which version of NT
  443. // is running on this machine
  444. //
  445. // Arguments:
  446. // LPCWSTR - machine name
  447. // NTVERSION*
  448. //
  449. // Returns: HRESULT
  450. //
  451. // History: MKarki Created 06/08/98
  452. //
  453. //----------------------------------------------------------------
  454. HRESULT
  455. GetNTVersion (
  456. /*[in]*/ LPCWSTR lpComputerName,
  457. /*[out]*/ NTVERSION *pNtVersion
  458. )
  459. {
  460. HRESULT hr = S_OK;
  461. _ASSERT ((NULL != lpComputerName) && (NULL != pNtVersion));
  462. do
  463. {
  464. //
  465. // get level 100 workstation information
  466. //
  467. PWKSTA_INFO_100 pInfo = NULL;
  468. DWORD dwErr = ::NetWkstaGetInfo (
  469. (LPWSTR)lpComputerName,
  470. 100,
  471. (LPBYTE*)&pInfo
  472. );
  473. if (NERR_Success != dwErr)
  474. {
  475. IASTracePrintf(
  476. "Error in SDO - GetNTVersion()"
  477. "- NTWkstaGetInfo failed with error:%d",
  478. dwErr
  479. );
  480. hr = HRESULT_FROM_WIN32 (dwErr);
  481. break;
  482. }
  483. //
  484. // get the version info
  485. //
  486. if (4 == pInfo->wki100_ver_major)
  487. {
  488. *pNtVersion = NTVERSION_4;
  489. }
  490. else if ( 5 == pInfo->wki100_ver_major)
  491. {
  492. *pNtVersion = NTVERSION_5;
  493. }
  494. else
  495. {
  496. IASTracePrintf(
  497. "Error in SDO - GetNTVersion()"
  498. " - Unsupported OS version..."
  499. );
  500. hr = E_FAIL;
  501. }
  502. } while (FALSE);
  503. return (hr);
  504. } // end of ::GetNTVersion method
  505. //++--------------------------------------------------------------
  506. //
  507. // Function: IsMixedDomain
  508. //
  509. // Synopsis: This is method determines which version of NT
  510. // is running on this machine
  511. //
  512. // Arguments:
  513. // [in] LPCWSTR - machine name
  514. // [out] PBOOL - is mixed
  515. //
  516. // Returns: HRESULT
  517. //
  518. // History: MKarki Created 06/08/98
  519. //
  520. //----------------------------------------------------------------
  521. HRESULT
  522. IsMixedDomain (
  523. /*[in]*/ LPCWSTR pszDomainName,
  524. /*[out]*/ PBOOL pbIsMixed
  525. )
  526. {
  527. HRESULT hr = S_OK;
  528. WCHAR szTempName [MAX_DOMAINNAME_LENGTH + 8];
  529. _ASSERT ((NULL != pszDomainName) && (NULL != pbIsMixed));
  530. do
  531. {
  532. //
  533. // check the arguments passedin
  534. //
  535. if ((NULL == pszDomainName) || (NULL == pbIsMixed))
  536. {
  537. IASTracePrintf(
  538. "Error in SDO - IsMixedDomain()"
  539. " - Invalid parameter - NULL"
  540. );
  541. hr = E_INVALIDARG;
  542. break;
  543. }
  544. if (::wcslen (pszDomainName) > MAX_DOMAINNAME_LENGTH)
  545. {
  546. IASTracePrintf(
  547. "Error in SDO - IsMixedDomain()"
  548. " - Invalid parameter (domain name is to long)..."
  549. );
  550. hr = E_FAIL;
  551. break;
  552. }
  553. //
  554. // form the DN name
  555. //
  556. wcscpy (szTempName, L"LDAP://");
  557. wcscat (szTempName, pszDomainName);
  558. //
  559. // get the domain object
  560. //
  561. CComPtr <IADs> pIADs;
  562. hr = ::ADsGetObject (
  563. szTempName,
  564. IID_IADs,
  565. reinterpret_cast <PVOID*> (&pIADs)
  566. );
  567. if (FAILED (hr))
  568. {
  569. IASTracePrintf(
  570. "Error in SDO - IsMixedDomain()"
  571. " - Could not get the domain object from the DS with error:%x",
  572. hr
  573. );
  574. break;
  575. }
  576. //
  577. // get the Mixed Domain info
  578. //
  579. _variant_t varMixedInfo;
  580. hr = pIADs->Get (L"nTMixedDomain", &varMixedInfo);
  581. if (FAILED (hr))
  582. {
  583. if (E_ADS_PROPERTY_NOT_FOUND == hr)
  584. {
  585. //
  586. // this is OK
  587. //
  588. *pbIsMixed = FALSE;
  589. hr = S_OK;
  590. }
  591. else
  592. {
  593. IASTracePrintf(
  594. "Error in SDO - IsMixedDomain()"
  595. "- Could not get the 'nTMixedDomain' property"
  596. "from the domain object, failed with error:%x",
  597. hr
  598. );
  599. }
  600. break;
  601. }
  602. _ASSERT (
  603. (VT_BOOL == V_VT (&varMixedInfo)) ||
  604. (VT_I4 == V_VT (&varMixedInfo))
  605. );
  606. //
  607. // get the values from the variant
  608. //
  609. if (VT_I4 == V_VT (&varMixedInfo))
  610. {
  611. *pbIsMixed = V_I4 (&varMixedInfo);
  612. }
  613. else if (VT_BOOL == V_VT (&varMixedInfo))
  614. {
  615. *pbIsMixed = (VARIANT_TRUE == V_BOOL (&varMixedInfo));
  616. }
  617. else
  618. {
  619. IASTracePrintf(
  620. "Error in SDO - IsMixedDomain()"
  621. "-'nTMixedDomain property has an invalid value..."
  622. );
  623. hr = E_FAIL;
  624. break;
  625. }
  626. } while (FALSE);
  627. return (hr);
  628. } // end of IsMixedDomain
  629. //++--------------------------------------------------------------
  630. //
  631. // Function: SdoGetDomainName
  632. //
  633. // Synopsis: This is method determines the domain name
  634. // given the server name
  635. //
  636. // Arguments:
  637. // LPCWSTR - machine name
  638. // LPWSTR - pDomanName
  639. //
  640. // Returns: HRESULT
  641. //
  642. // History: MKarki Created 06/08/98
  643. //
  644. //----------------------------------------------------------------
  645. HRESULT
  646. SdoGetDomainName (
  647. /*[in]*/ LPCWSTR pszServerName,
  648. /*[out]*/ LPWSTR pDomainName
  649. )
  650. {
  651. _ASSERT (NULL != pDomainName);
  652. #if 0
  653. SERVER_INFO_503 ServerInfo;
  654. ServerInfo.sv503_domain = pDomainName;
  655. DWORD dwErr = ::NetServerGetInfo (
  656. const_cast <LPWSTR> (pszServerName),
  657. 503,
  658. reinterpret_cast <LPBYTE*> (&ServerInfo)
  659. );
  660. if (NERR_Success != dwErr)
  661. {
  662. IASTracePrintf("Error in SDO - SdoGetDomainName() - NetServerGetInfo() failed...");
  663. return (HRESULT_FROM_WIN32 (dwErr));
  664. }
  665. return (S_OK);
  666. #endif
  667. return (E_FAIL);
  668. } // end of ::SdoGetDomainName method